diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-13 13:12:15 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-13 13:12:15 -0400 |
commit | c8c55bcb43d790d97790cfa319d80045a71fde39 (patch) | |
tree | b791d9478d3e7f1eb26e51bb999fde21847d4391 /fs | |
parent | 3749c66c67fb5c257771815c186bc32290cacf44 (diff) | |
parent | ebf8889bd1fe3615991ff4494635d237280652a2 (diff) |
Merge git://git.infradead.org/mtd-2.6
* git://git.infradead.org/mtd-2.6: (91 commits)
[MTD] [NAND] Blackfin on-chip NAND Flash Controller driver
[MTD] [NOR] fix ctrl-alt-del can't reboot for intel flash bug
[MTD] [NAND] Fix compiler warning in Alauda driver
[JFFS2] Remove stray debugging printk
[JFFS2] Handle dirents on the flash with embedded zero bytes in names.
[JFFS2] Check for creation of dirents with embedded zero bytes in name.
[JFFS2] Don't count all 'very dirty' blocks except in debug mode
[JFFS2] Check whether garbage-collection actually obsoleted its victim.
[JFFS2] Relax threshold for triggering GC due to dirty blocks.
[MTD] [OneNAND] Fix typo related with recent commit
[JFFS2] Trigger garbage collection when very_dirty_list size becomes excessive
[MTD] [NAND] Avoid deadlock in erase callback; release chip lock first.
[MTD] [NAND] Resume method for CAFÉ NAND controller
[MTD] [NAND] Fix PCI ident table for CAFÉ NAND controller.
[MTD] [NAND] s3c2410: fix arch moves
[MTD] [OneNAND] fix numerous races
[MTD] map driver for NOR flash on the Intel Vermilion Range chipset
[JFFS2] Fix unpoint length
[MTD] fix CFI point method for discontiguous maps
[MTD] MAPS: Merge Lubbock and Mainstone drivers into common PXA2xx driver
...
Diffstat (limited to 'fs')
-rw-r--r-- | fs/Kconfig | 81 | ||||
-rw-r--r-- | fs/jffs2/Makefile | 1 | ||||
-rw-r--r-- | fs/jffs2/acl.c | 23 | ||||
-rw-r--r-- | fs/jffs2/acl.h | 4 | ||||
-rw-r--r-- | fs/jffs2/background.c | 4 | ||||
-rw-r--r-- | fs/jffs2/build.c | 10 | ||||
-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 | 37 | ||||
-rw-r--r-- | fs/jffs2/erase.c | 57 | ||||
-rw-r--r-- | fs/jffs2/fs.c | 32 | ||||
-rw-r--r-- | fs/jffs2/gc.c | 23 | ||||
-rw-r--r-- | fs/jffs2/jffs2_fs_sb.h | 5 | ||||
-rw-r--r-- | fs/jffs2/nodelist.h | 2 | ||||
-rw-r--r-- | fs/jffs2/nodemgmt.c | 25 | ||||
-rw-r--r-- | fs/jffs2/os-linux.h | 5 | ||||
-rw-r--r-- | fs/jffs2/readinode.c | 8 | ||||
-rw-r--r-- | fs/jffs2/scan.c | 19 | ||||
-rw-r--r-- | fs/jffs2/security.c | 6 | ||||
-rw-r--r-- | fs/jffs2/summary.c | 30 | ||||
-rw-r--r-- | fs/jffs2/summary.h | 6 | ||||
-rw-r--r-- | fs/jffs2/wbuf.c | 81 | ||||
-rw-r--r-- | fs/jffs2/write.c | 13 | ||||
-rw-r--r-- | fs/jffs2/xattr.h | 2 | ||||
-rw-r--r-- | fs/jffs2/xattr_user.c | 4 |
29 files changed, 736 insertions, 338 deletions
diff --git a/fs/Kconfig b/fs/Kconfig index f9eed6d79066..bb02b39380a3 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
@@ -1225,6 +1225,14 @@ config JFFS2_FS_WRITEBUFFER | |||
1225 | - NOR flash with transparent ECC | 1225 | - NOR flash with transparent ECC |
1226 | - DataFlash | 1226 | - DataFlash |
1227 | 1227 | ||
1228 | config JFFS2_FS_WBUF_VERIFY | ||
1229 | bool "Verify JFFS2 write-buffer reads" | ||
1230 | depends on JFFS2_FS_WRITEBUFFER | ||
1231 | default n | ||
1232 | help | ||
1233 | This causes JFFS2 to read back every page written through the | ||
1234 | write-buffer, and check for errors. | ||
1235 | |||
1228 | config JFFS2_SUMMARY | 1236 | config JFFS2_SUMMARY |
1229 | bool "JFFS2 summary support (EXPERIMENTAL)" | 1237 | bool "JFFS2 summary support (EXPERIMENTAL)" |
1230 | depends on JFFS2_FS && EXPERIMENTAL | 1238 | depends on JFFS2_FS && EXPERIMENTAL |
@@ -1295,52 +1303,71 @@ config JFFS2_ZLIB | |||
1295 | select ZLIB_DEFLATE | 1303 | select ZLIB_DEFLATE |
1296 | depends on JFFS2_FS | 1304 | depends on JFFS2_FS |
1297 | default y | 1305 | default y |
1298 | help | 1306 | help |
1299 | Zlib is designed to be a free, general-purpose, legally unencumbered, | 1307 | Zlib is designed to be a free, general-purpose, legally unencumbered, |
1300 | lossless data-compression library for use on virtually any computer | 1308 | lossless data-compression library for use on virtually any computer |
1301 | hardware and operating system. See <http://www.gzip.org/zlib/> for | 1309 | hardware and operating system. See <http://www.gzip.org/zlib/> for |
1302 | further information. | 1310 | further information. |
1303 | 1311 | ||
1304 | Say 'Y' if unsure. | 1312 | Say 'Y' if unsure. |
1313 | |||
1314 | config JFFS2_LZO | ||
1315 | bool "JFFS2 LZO compression support" if JFFS2_COMPRESSION_OPTIONS | ||
1316 | select LZO_COMPRESS | ||
1317 | select LZO_DECOMPRESS | ||
1318 | depends on JFFS2_FS | ||
1319 | default n | ||
1320 | help | ||
1321 | minilzo-based compression. Generally works better than Zlib. | ||
1322 | |||
1323 | This feature was added in July, 2007. Say 'N' if you need | ||
1324 | compatibility with older bootloaders or kernels. | ||
1305 | 1325 | ||
1306 | config JFFS2_RTIME | 1326 | config JFFS2_RTIME |
1307 | bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS | 1327 | bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS |
1308 | depends on JFFS2_FS | 1328 | depends on JFFS2_FS |
1309 | default y | 1329 | default y |
1310 | help | 1330 | help |
1311 | Rtime does manage to recompress already-compressed data. Say 'Y' if unsure. | 1331 | Rtime does manage to recompress already-compressed data. Say 'Y' if unsure. |
1312 | 1332 | ||
1313 | config JFFS2_RUBIN | 1333 | config JFFS2_RUBIN |
1314 | bool "JFFS2 RUBIN compression support" if JFFS2_COMPRESSION_OPTIONS | 1334 | bool "JFFS2 RUBIN compression support" if JFFS2_COMPRESSION_OPTIONS |
1315 | depends on JFFS2_FS | 1335 | depends on JFFS2_FS |
1316 | default n | 1336 | default n |
1317 | help | 1337 | help |
1318 | RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure. | 1338 | RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure. |
1319 | 1339 | ||
1320 | choice | 1340 | choice |
1321 | prompt "JFFS2 default compression mode" if JFFS2_COMPRESSION_OPTIONS | 1341 | prompt "JFFS2 default compression mode" if JFFS2_COMPRESSION_OPTIONS |
1322 | default JFFS2_CMODE_PRIORITY | 1342 | default JFFS2_CMODE_PRIORITY |
1323 | depends on JFFS2_FS | 1343 | depends on JFFS2_FS |
1324 | help | 1344 | help |
1325 | You can set here the default compression mode of JFFS2 from | 1345 | You can set here the default compression mode of JFFS2 from |
1326 | the available compression modes. Don't touch if unsure. | 1346 | the available compression modes. Don't touch if unsure. |
1327 | 1347 | ||
1328 | config JFFS2_CMODE_NONE | 1348 | config JFFS2_CMODE_NONE |
1329 | bool "no compression" | 1349 | bool "no compression" |
1330 | help | 1350 | help |
1331 | Uses no compression. | 1351 | Uses no compression. |
1332 | 1352 | ||
1333 | config JFFS2_CMODE_PRIORITY | 1353 | config JFFS2_CMODE_PRIORITY |
1334 | bool "priority" | 1354 | bool "priority" |
1335 | help | 1355 | help |
1336 | Tries the compressors in a predefined order and chooses the first | 1356 | Tries the compressors in a predefined order and chooses the first |
1337 | successful one. | 1357 | successful one. |
1338 | 1358 | ||
1339 | config JFFS2_CMODE_SIZE | 1359 | config JFFS2_CMODE_SIZE |
1340 | bool "size (EXPERIMENTAL)" | 1360 | bool "size (EXPERIMENTAL)" |
1341 | help | 1361 | help |
1342 | Tries all compressors and chooses the one which has the smallest | 1362 | Tries all compressors and chooses the one which has the smallest |
1343 | result. | 1363 | result. |
1364 | |||
1365 | config JFFS2_CMODE_FAVOURLZO | ||
1366 | bool "Favour LZO" | ||
1367 | help | ||
1368 | Tries all compressors and chooses the one which has the smallest | ||
1369 | result but gives some preference to LZO (which has faster | ||
1370 | decompression) at the expense of size. | ||
1344 | 1371 | ||
1345 | endchoice | 1372 | endchoice |
1346 | 1373 | ||
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/acl.c b/fs/jffs2/acl.c index 65b3a1b5b88d..8ec9323e830a 100644 --- a/fs/jffs2/acl.c +++ b/fs/jffs2/acl.c | |||
@@ -176,7 +176,7 @@ static void jffs2_iset_acl(struct inode *inode, struct posix_acl **i_acl, struct | |||
176 | spin_unlock(&inode->i_lock); | 176 | spin_unlock(&inode->i_lock); |
177 | } | 177 | } |
178 | 178 | ||
179 | static struct posix_acl *jffs2_get_acl(struct inode *inode, int type) | 179 | struct posix_acl *jffs2_get_acl(struct inode *inode, int type) |
180 | { | 180 | { |
181 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); | 181 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); |
182 | struct posix_acl *acl; | 182 | struct posix_acl *acl; |
@@ -247,8 +247,13 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) | |||
247 | if (rc < 0) | 247 | if (rc < 0) |
248 | return rc; | 248 | return rc; |
249 | if (inode->i_mode != mode) { | 249 | if (inode->i_mode != mode) { |
250 | inode->i_mode = mode; | 250 | struct iattr attr; |
251 | jffs2_dirty_inode(inode); | 251 | |
252 | attr.ia_valid = ATTR_MODE; | ||
253 | attr.ia_mode = mode; | ||
254 | rc = jffs2_do_setattr(inode, &attr); | ||
255 | if (rc < 0) | ||
256 | return rc; | ||
252 | } | 257 | } |
253 | if (rc == 0) | 258 | if (rc == 0) |
254 | acl = NULL; | 259 | acl = NULL; |
@@ -307,22 +312,16 @@ int jffs2_permission(struct inode *inode, int mask, struct nameidata *nd) | |||
307 | return generic_permission(inode, mask, jffs2_check_acl); | 312 | return generic_permission(inode, mask, jffs2_check_acl); |
308 | } | 313 | } |
309 | 314 | ||
310 | int jffs2_init_acl(struct inode *inode, struct inode *dir) | 315 | int jffs2_init_acl(struct inode *inode, struct posix_acl *acl) |
311 | { | 316 | { |
312 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); | 317 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); |
313 | struct posix_acl *acl = NULL, *clone; | 318 | struct posix_acl *clone; |
314 | mode_t mode; | 319 | mode_t mode; |
315 | int rc = 0; | 320 | int rc = 0; |
316 | 321 | ||
317 | f->i_acl_access = JFFS2_ACL_NOT_CACHED; | 322 | f->i_acl_access = JFFS2_ACL_NOT_CACHED; |
318 | f->i_acl_default = JFFS2_ACL_NOT_CACHED; | 323 | f->i_acl_default = JFFS2_ACL_NOT_CACHED; |
319 | if (!S_ISLNK(inode->i_mode)) { | 324 | |
320 | acl = jffs2_get_acl(dir, ACL_TYPE_DEFAULT); | ||
321 | if (IS_ERR(acl)) | ||
322 | return PTR_ERR(acl); | ||
323 | if (!acl) | ||
324 | inode->i_mode &= ~current->fs->umask; | ||
325 | } | ||
326 | if (acl) { | 325 | if (acl) { |
327 | if (S_ISDIR(inode->i_mode)) { | 326 | if (S_ISDIR(inode->i_mode)) { |
328 | rc = jffs2_set_acl(inode, ACL_TYPE_DEFAULT, acl); | 327 | rc = jffs2_set_acl(inode, ACL_TYPE_DEFAULT, acl); |
diff --git a/fs/jffs2/acl.h b/fs/jffs2/acl.h index c84378cee82a..90a2dbf59051 100644 --- a/fs/jffs2/acl.h +++ b/fs/jffs2/acl.h | |||
@@ -28,9 +28,10 @@ struct jffs2_acl_header { | |||
28 | 28 | ||
29 | #define JFFS2_ACL_NOT_CACHED ((void *)-1) | 29 | #define JFFS2_ACL_NOT_CACHED ((void *)-1) |
30 | 30 | ||
31 | extern struct posix_acl *jffs2_get_acl(struct inode *inode, int type); | ||
31 | extern int jffs2_permission(struct inode *, int, struct nameidata *); | 32 | extern int jffs2_permission(struct inode *, int, struct nameidata *); |
32 | extern int jffs2_acl_chmod(struct inode *); | 33 | extern int jffs2_acl_chmod(struct inode *); |
33 | extern int jffs2_init_acl(struct inode *, struct inode *); | 34 | extern int jffs2_init_acl(struct inode *, struct posix_acl *); |
34 | extern void jffs2_clear_acl(struct jffs2_inode_info *); | 35 | extern void jffs2_clear_acl(struct jffs2_inode_info *); |
35 | 36 | ||
36 | extern struct xattr_handler jffs2_acl_access_xattr_handler; | 37 | extern struct xattr_handler jffs2_acl_access_xattr_handler; |
@@ -38,6 +39,7 @@ extern struct xattr_handler jffs2_acl_default_xattr_handler; | |||
38 | 39 | ||
39 | #else | 40 | #else |
40 | 41 | ||
42 | #define jffs2_get_acl(inode, type) (NULL) | ||
41 | #define jffs2_permission NULL | 43 | #define jffs2_permission NULL |
42 | #define jffs2_acl_chmod(inode) (0) | 44 | #define jffs2_acl_chmod(inode) (0) |
43 | #define jffs2_init_acl(inode,dir) (0) | 45 | #define jffs2_init_acl(inode,dir) (0) |
diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index 504643f2e98b..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 | ||
diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c index 0ca2fff2617f..722a6b682951 100644 --- a/fs/jffs2/build.c +++ b/fs/jffs2/build.c | |||
@@ -285,6 +285,14 @@ static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c) | |||
285 | than actually making progress? */ | 285 | than actually making progress? */ |
286 | c->resv_blocks_gcbad = 0;//c->resv_blocks_deletion + 2; | 286 | c->resv_blocks_gcbad = 0;//c->resv_blocks_deletion + 2; |
287 | 287 | ||
288 | /* What number of 'very dirty' eraseblocks do we allow before we | ||
289 | trigger the GC thread even if we don't _need_ the space. When we | ||
290 | can't mark nodes obsolete on the medium, the old dirty nodes cause | ||
291 | performance problems because we have to inspect and discard them. */ | ||
292 | c->vdirty_blocks_gctrigger = c->resv_blocks_gctrigger; | ||
293 | if (jffs2_can_mark_obsolete(c)) | ||
294 | c->vdirty_blocks_gctrigger *= 10; | ||
295 | |||
288 | /* If there's less than this amount of dirty space, don't bother | 296 | /* If there's less than this amount of dirty space, don't bother |
289 | trying to GC to make more space. It'll be a fruitless task */ | 297 | trying to GC to make more space. It'll be a fruitless task */ |
290 | c->nospc_dirty_size = c->sector_size + (c->flash_size / 100); | 298 | c->nospc_dirty_size = c->sector_size + (c->flash_size / 100); |
@@ -303,6 +311,8 @@ static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c) | |||
303 | c->resv_blocks_gcbad, c->resv_blocks_gcbad*c->sector_size/1024); | 311 | c->resv_blocks_gcbad, c->resv_blocks_gcbad*c->sector_size/1024); |
304 | dbg_fsbuild("Amount of dirty space required to GC: %d bytes\n", | 312 | dbg_fsbuild("Amount of dirty space required to GC: %d bytes\n", |
305 | c->nospc_dirty_size); | 313 | c->nospc_dirty_size); |
314 | dbg_fsbuild("Very dirty blocks before GC triggered: %d\n", | ||
315 | c->vdirty_blocks_gctrigger); | ||
306 | } | 316 | } |
307 | 317 | ||
308 | int jffs2_do_mount_fs(struct jffs2_sb_info *c) | 318 | int jffs2_do_mount_fs(struct jffs2_sb_info *c) |
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..8353eb9c1799 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 | { |
@@ -182,6 +182,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, | |||
182 | struct jffs2_inode_info *f, *dir_f; | 182 | struct jffs2_inode_info *f, *dir_f; |
183 | struct jffs2_sb_info *c; | 183 | struct jffs2_sb_info *c; |
184 | struct inode *inode; | 184 | struct inode *inode; |
185 | struct posix_acl *acl; | ||
185 | int ret; | 186 | int ret; |
186 | 187 | ||
187 | ri = jffs2_alloc_raw_inode(); | 188 | ri = jffs2_alloc_raw_inode(); |
@@ -192,7 +193,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, | |||
192 | 193 | ||
193 | D1(printk(KERN_DEBUG "jffs2_create()\n")); | 194 | D1(printk(KERN_DEBUG "jffs2_create()\n")); |
194 | 195 | ||
195 | inode = jffs2_new_inode(dir_i, mode, ri); | 196 | inode = jffs2_new_inode(dir_i, mode, ri, &acl); |
196 | 197 | ||
197 | if (IS_ERR(inode)) { | 198 | if (IS_ERR(inode)) { |
198 | D1(printk(KERN_DEBUG "jffs2_new_inode() failed\n")); | 199 | D1(printk(KERN_DEBUG "jffs2_new_inode() failed\n")); |
@@ -212,12 +213,12 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, | |||
212 | dentry->d_name.name, dentry->d_name.len); | 213 | dentry->d_name.name, dentry->d_name.len); |
213 | 214 | ||
214 | if (ret) | 215 | if (ret) |
215 | goto fail; | 216 | goto fail_acl; |
216 | 217 | ||
217 | ret = jffs2_init_security(inode, dir_i); | 218 | ret = jffs2_init_security(inode, dir_i); |
218 | if (ret) | 219 | if (ret) |
219 | goto fail; | 220 | goto fail_acl; |
220 | ret = jffs2_init_acl(inode, dir_i); | 221 | ret = jffs2_init_acl(inode, acl); |
221 | if (ret) | 222 | if (ret) |
222 | goto fail; | 223 | goto fail; |
223 | 224 | ||
@@ -230,6 +231,8 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, | |||
230 | inode->i_ino, inode->i_mode, inode->i_nlink, f->inocache->nlink, inode->i_mapping->nrpages)); | 231 | inode->i_ino, inode->i_mode, inode->i_nlink, f->inocache->nlink, inode->i_mapping->nrpages)); |
231 | return 0; | 232 | return 0; |
232 | 233 | ||
234 | fail_acl: | ||
235 | posix_acl_release(acl); | ||
233 | fail: | 236 | fail: |
234 | make_bad_inode(inode); | 237 | make_bad_inode(inode); |
235 | iput(inode); | 238 | iput(inode); |
@@ -306,6 +309,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
306 | struct jffs2_full_dirent *fd; | 309 | struct jffs2_full_dirent *fd; |
307 | int namelen; | 310 | int namelen; |
308 | uint32_t alloclen; | 311 | uint32_t alloclen; |
312 | struct posix_acl *acl; | ||
309 | int ret, targetlen = strlen(target); | 313 | int ret, targetlen = strlen(target); |
310 | 314 | ||
311 | /* FIXME: If you care. We'd need to use frags for the target | 315 | /* FIXME: If you care. We'd need to use frags for the target |
@@ -332,7 +336,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
332 | return ret; | 336 | return ret; |
333 | } | 337 | } |
334 | 338 | ||
335 | inode = jffs2_new_inode(dir_i, S_IFLNK | S_IRWXUGO, ri); | 339 | inode = jffs2_new_inode(dir_i, S_IFLNK | S_IRWXUGO, ri, &acl); |
336 | 340 | ||
337 | if (IS_ERR(inode)) { | 341 | if (IS_ERR(inode)) { |
338 | jffs2_free_raw_inode(ri); | 342 | jffs2_free_raw_inode(ri); |
@@ -362,6 +366,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
362 | up(&f->sem); | 366 | up(&f->sem); |
363 | jffs2_complete_reservation(c); | 367 | jffs2_complete_reservation(c); |
364 | jffs2_clear_inode(inode); | 368 | jffs2_clear_inode(inode); |
369 | posix_acl_release(acl); | ||
365 | return PTR_ERR(fn); | 370 | return PTR_ERR(fn); |
366 | } | 371 | } |
367 | 372 | ||
@@ -372,6 +377,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
372 | up(&f->sem); | 377 | up(&f->sem); |
373 | jffs2_complete_reservation(c); | 378 | jffs2_complete_reservation(c); |
374 | jffs2_clear_inode(inode); | 379 | jffs2_clear_inode(inode); |
380 | posix_acl_release(acl); | ||
375 | return -ENOMEM; | 381 | return -ENOMEM; |
376 | } | 382 | } |
377 | 383 | ||
@@ -389,9 +395,10 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
389 | ret = jffs2_init_security(inode, dir_i); | 395 | ret = jffs2_init_security(inode, dir_i); |
390 | if (ret) { | 396 | if (ret) { |
391 | jffs2_clear_inode(inode); | 397 | jffs2_clear_inode(inode); |
398 | posix_acl_release(acl); | ||
392 | return ret; | 399 | return ret; |
393 | } | 400 | } |
394 | ret = jffs2_init_acl(inode, dir_i); | 401 | ret = jffs2_init_acl(inode, acl); |
395 | if (ret) { | 402 | if (ret) { |
396 | jffs2_clear_inode(inode); | 403 | jffs2_clear_inode(inode); |
397 | return ret; | 404 | return ret; |
@@ -469,6 +476,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) | |||
469 | struct jffs2_full_dirent *fd; | 476 | struct jffs2_full_dirent *fd; |
470 | int namelen; | 477 | int namelen; |
471 | uint32_t alloclen; | 478 | uint32_t alloclen; |
479 | struct posix_acl *acl; | ||
472 | int ret; | 480 | int ret; |
473 | 481 | ||
474 | mode |= S_IFDIR; | 482 | mode |= S_IFDIR; |
@@ -491,7 +499,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) | |||
491 | return ret; | 499 | return ret; |
492 | } | 500 | } |
493 | 501 | ||
494 | inode = jffs2_new_inode(dir_i, mode, ri); | 502 | inode = jffs2_new_inode(dir_i, mode, ri, &acl); |
495 | 503 | ||
496 | if (IS_ERR(inode)) { | 504 | if (IS_ERR(inode)) { |
497 | jffs2_free_raw_inode(ri); | 505 | jffs2_free_raw_inode(ri); |
@@ -518,6 +526,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) | |||
518 | up(&f->sem); | 526 | up(&f->sem); |
519 | jffs2_complete_reservation(c); | 527 | jffs2_complete_reservation(c); |
520 | jffs2_clear_inode(inode); | 528 | jffs2_clear_inode(inode); |
529 | posix_acl_release(acl); | ||
521 | return PTR_ERR(fn); | 530 | return PTR_ERR(fn); |
522 | } | 531 | } |
523 | /* No data here. Only a metadata node, which will be | 532 | /* No data here. Only a metadata node, which will be |
@@ -531,9 +540,10 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) | |||
531 | ret = jffs2_init_security(inode, dir_i); | 540 | ret = jffs2_init_security(inode, dir_i); |
532 | if (ret) { | 541 | if (ret) { |
533 | jffs2_clear_inode(inode); | 542 | jffs2_clear_inode(inode); |
543 | posix_acl_release(acl); | ||
534 | return ret; | 544 | return ret; |
535 | } | 545 | } |
536 | ret = jffs2_init_acl(inode, dir_i); | 546 | ret = jffs2_init_acl(inode, acl); |
537 | if (ret) { | 547 | if (ret) { |
538 | jffs2_clear_inode(inode); | 548 | jffs2_clear_inode(inode); |
539 | return ret; | 549 | return ret; |
@@ -629,6 +639,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de | |||
629 | union jffs2_device_node dev; | 639 | union jffs2_device_node dev; |
630 | int devlen = 0; | 640 | int devlen = 0; |
631 | uint32_t alloclen; | 641 | uint32_t alloclen; |
642 | struct posix_acl *acl; | ||
632 | int ret; | 643 | int ret; |
633 | 644 | ||
634 | if (!new_valid_dev(rdev)) | 645 | if (!new_valid_dev(rdev)) |
@@ -655,7 +666,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de | |||
655 | return ret; | 666 | return ret; |
656 | } | 667 | } |
657 | 668 | ||
658 | inode = jffs2_new_inode(dir_i, mode, ri); | 669 | inode = jffs2_new_inode(dir_i, mode, ri, &acl); |
659 | 670 | ||
660 | if (IS_ERR(inode)) { | 671 | if (IS_ERR(inode)) { |
661 | jffs2_free_raw_inode(ri); | 672 | jffs2_free_raw_inode(ri); |
@@ -684,6 +695,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de | |||
684 | up(&f->sem); | 695 | up(&f->sem); |
685 | jffs2_complete_reservation(c); | 696 | jffs2_complete_reservation(c); |
686 | jffs2_clear_inode(inode); | 697 | jffs2_clear_inode(inode); |
698 | posix_acl_release(acl); | ||
687 | return PTR_ERR(fn); | 699 | return PTR_ERR(fn); |
688 | } | 700 | } |
689 | /* No data here. Only a metadata node, which will be | 701 | /* No data here. Only a metadata node, which will be |
@@ -697,9 +709,10 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de | |||
697 | ret = jffs2_init_security(inode, dir_i); | 709 | ret = jffs2_init_security(inode, dir_i); |
698 | if (ret) { | 710 | if (ret) { |
699 | jffs2_clear_inode(inode); | 711 | jffs2_clear_inode(inode); |
712 | posix_acl_release(acl); | ||
700 | return ret; | 713 | return ret; |
701 | } | 714 | } |
702 | ret = jffs2_init_acl(inode, dir_i); | 715 | ret = jffs2_init_acl(inode, acl); |
703 | if (ret) { | 716 | if (ret) { |
704 | jffs2_clear_inode(inode); | 717 | jffs2_clear_inode(inode); |
705 | return ret; | 718 | return ret; |
@@ -770,7 +783,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de | |||
770 | } | 783 | } |
771 | 784 | ||
772 | static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, | 785 | static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, |
773 | struct inode *new_dir_i, struct dentry *new_dentry) | 786 | struct inode *new_dir_i, struct dentry *new_dentry) |
774 | { | 787 | { |
775 | int ret; | 788 | int ret; |
776 | struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); | 789 | 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..a1db9180633f 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, retlen); | ||
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%08tx\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); |
@@ -362,7 +401,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb | |||
362 | { | 401 | { |
363 | size_t retlen; | 402 | size_t retlen; |
364 | int ret; | 403 | int ret; |
365 | uint32_t bad_offset; | 404 | uint32_t uninitialized_var(bad_offset); |
366 | 405 | ||
367 | switch (jffs2_block_check_erase(c, jeb, &bad_offset)) { | 406 | switch (jffs2_block_check_erase(c, jeb, &bad_offset)) { |
368 | case -EAGAIN: goto refile; | 407 | case -EAGAIN: goto refile; |
@@ -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/fs.c b/fs/jffs2/fs.c index 8bc727b71696..ed85f9afdbc8 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c | |||
@@ -24,7 +24,7 @@ | |||
24 | 24 | ||
25 | static int jffs2_flash_setup(struct jffs2_sb_info *c); | 25 | static int jffs2_flash_setup(struct jffs2_sb_info *c); |
26 | 26 | ||
27 | static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) | 27 | int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) |
28 | { | 28 | { |
29 | struct jffs2_full_dnode *old_metadata, *new_metadata; | 29 | struct jffs2_full_dnode *old_metadata, *new_metadata; |
30 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); | 30 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); |
@@ -36,10 +36,8 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) | |||
36 | unsigned int ivalid; | 36 | unsigned int ivalid; |
37 | uint32_t alloclen; | 37 | uint32_t alloclen; |
38 | int ret; | 38 | int ret; |
39 | |||
39 | D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino)); | 40 | D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino)); |
40 | ret = inode_change_ok(inode, iattr); | ||
41 | if (ret) | ||
42 | return ret; | ||
43 | 41 | ||
44 | /* Special cases - we don't want more than one data node | 42 | /* Special cases - we don't want more than one data node |
45 | for these types on the medium at any time. So setattr | 43 | for these types on the medium at any time. So setattr |
@@ -183,9 +181,14 @@ int jffs2_setattr(struct dentry *dentry, struct iattr *iattr) | |||
183 | { | 181 | { |
184 | int rc; | 182 | int rc; |
185 | 183 | ||
184 | rc = inode_change_ok(dentry->d_inode, iattr); | ||
185 | if (rc) | ||
186 | return rc; | ||
187 | |||
186 | rc = jffs2_do_setattr(dentry->d_inode, iattr); | 188 | rc = jffs2_do_setattr(dentry->d_inode, iattr); |
187 | if (!rc && (iattr->ia_valid & ATTR_MODE)) | 189 | if (!rc && (iattr->ia_valid & ATTR_MODE)) |
188 | rc = jffs2_acl_chmod(dentry->d_inode); | 190 | rc = jffs2_acl_chmod(dentry->d_inode); |
191 | |||
189 | return rc; | 192 | return rc; |
190 | } | 193 | } |
191 | 194 | ||
@@ -399,7 +402,8 @@ void jffs2_write_super (struct super_block *sb) | |||
399 | 402 | ||
400 | /* jffs2_new_inode: allocate a new inode and inocache, add it to the hash, | 403 | /* jffs2_new_inode: allocate a new inode and inocache, add it to the hash, |
401 | fill in the raw_inode while you're at it. */ | 404 | fill in the raw_inode while you're at it. */ |
402 | struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri) | 405 | struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri, |
406 | struct posix_acl **acl) | ||
403 | { | 407 | { |
404 | struct inode *inode; | 408 | struct inode *inode; |
405 | struct super_block *sb = dir_i->i_sb; | 409 | struct super_block *sb = dir_i->i_sb; |
@@ -431,7 +435,23 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i | |||
431 | } else { | 435 | } else { |
432 | ri->gid = cpu_to_je16(current->fsgid); | 436 | ri->gid = cpu_to_je16(current->fsgid); |
433 | } | 437 | } |
434 | ri->mode = cpu_to_jemode(mode); | 438 | |
439 | /* POSIX ACLs have to be processed now, at least partly. | ||
440 | The umask is only applied if there's no default ACL */ | ||
441 | if (!S_ISLNK(mode)) { | ||
442 | *acl = jffs2_get_acl(dir_i, ACL_TYPE_DEFAULT); | ||
443 | if (IS_ERR(*acl)) { | ||
444 | make_bad_inode(inode); | ||
445 | iput(inode); | ||
446 | inode = (void *)*acl; | ||
447 | *acl = NULL; | ||
448 | return inode; | ||
449 | } | ||
450 | if (!(*acl)) | ||
451 | mode &= ~current->fs->umask; | ||
452 | } else { | ||
453 | *acl = NULL; | ||
454 | } | ||
435 | ret = jffs2_do_new_inode (c, f, mode, ri); | 455 | ret = jffs2_do_new_inode (c, f, mode, ri); |
436 | if (ret) { | 456 | if (ret) { |
437 | make_bad_inode(inode); | 457 | make_bad_inode(inode); |
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 2d99e06ab223..32ff0373aa04 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c | |||
@@ -122,6 +122,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
122 | struct jffs2_inode_cache *ic; | 122 | struct jffs2_inode_cache *ic; |
123 | struct jffs2_eraseblock *jeb; | 123 | struct jffs2_eraseblock *jeb; |
124 | struct jffs2_raw_node_ref *raw; | 124 | struct jffs2_raw_node_ref *raw; |
125 | uint32_t gcblock_dirty; | ||
125 | int ret = 0, inum, nlink; | 126 | int ret = 0, inum, nlink; |
126 | int xattr = 0; | 127 | int xattr = 0; |
127 | 128 | ||
@@ -236,6 +237,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
236 | } | 237 | } |
237 | 238 | ||
238 | raw = jeb->gc_node; | 239 | raw = jeb->gc_node; |
240 | gcblock_dirty = jeb->dirty_size; | ||
239 | 241 | ||
240 | while(ref_obsolete(raw)) { | 242 | while(ref_obsolete(raw)) { |
241 | D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", ref_offset(raw))); | 243 | D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", ref_offset(raw))); |
@@ -282,7 +284,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
282 | } else { | 284 | } else { |
283 | ret = jffs2_garbage_collect_xattr_ref(c, (struct jffs2_xattr_ref *)ic, raw); | 285 | ret = jffs2_garbage_collect_xattr_ref(c, (struct jffs2_xattr_ref *)ic, raw); |
284 | } | 286 | } |
285 | goto release_sem; | 287 | goto test_gcnode; |
286 | } | 288 | } |
287 | #endif | 289 | #endif |
288 | 290 | ||
@@ -376,7 +378,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
376 | 378 | ||
377 | if (ret != -EBADFD) { | 379 | if (ret != -EBADFD) { |
378 | spin_unlock(&c->inocache_lock); | 380 | spin_unlock(&c->inocache_lock); |
379 | goto release_sem; | 381 | goto test_gcnode; |
380 | } | 382 | } |
381 | 383 | ||
382 | /* Fall through if it wanted us to, with inocache_lock held */ | 384 | /* Fall through if it wanted us to, with inocache_lock held */ |
@@ -407,6 +409,12 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
407 | 409 | ||
408 | jffs2_gc_release_inode(c, f); | 410 | jffs2_gc_release_inode(c, f); |
409 | 411 | ||
412 | test_gcnode: | ||
413 | if (jeb->dirty_size == gcblock_dirty && !ref_obsolete(jeb->gc_node)) { | ||
414 | /* Eep. This really should never happen. GC is broken */ | ||
415 | printk(KERN_ERR "Error garbage collecting node at %08x!\n", ref_offset(jeb->gc_node)); | ||
416 | ret = -ENOSPC; | ||
417 | } | ||
410 | release_sem: | 418 | release_sem: |
411 | up(&c->alloc_sem); | 419 | up(&c->alloc_sem); |
412 | 420 | ||
@@ -556,7 +564,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, | |||
556 | 564 | ||
557 | node = kmalloc(rawlen, GFP_KERNEL); | 565 | node = kmalloc(rawlen, GFP_KERNEL); |
558 | if (!node) | 566 | if (!node) |
559 | return -ENOMEM; | 567 | return -ENOMEM; |
560 | 568 | ||
561 | ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)node); | 569 | ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)node); |
562 | if (!ret && retlen != rawlen) | 570 | if (!ret && retlen != rawlen) |
@@ -598,10 +606,15 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, | |||
598 | goto bail; | 606 | goto bail; |
599 | } | 607 | } |
600 | 608 | ||
609 | if (strnlen(node->d.name, node->d.nsize) != node->d.nsize) { | ||
610 | printk(KERN_WARNING "Name in dirent node at 0x%08x contains zeroes\n", ref_offset(raw)); | ||
611 | goto bail; | ||
612 | } | ||
613 | |||
601 | if (node->d.nsize) { | 614 | if (node->d.nsize) { |
602 | crc = crc32(0, node->d.name, node->d.nsize); | 615 | crc = crc32(0, node->d.name, node->d.nsize); |
603 | if (je32_to_cpu(node->d.name_crc) != crc) { | 616 | if (je32_to_cpu(node->d.name_crc) != crc) { |
604 | printk(KERN_WARNING "Name CRC failed on REF_PRISTINE dirent ode at 0x%08x: Read 0x%08x, calculated 0x%08x\n", | 617 | printk(KERN_WARNING "Name CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", |
605 | ref_offset(raw), je32_to_cpu(node->d.name_crc), crc); | 618 | ref_offset(raw), je32_to_cpu(node->d.name_crc), crc); |
606 | goto bail; | 619 | goto bail; |
607 | } | 620 | } |
@@ -624,7 +637,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, | |||
624 | 637 | ||
625 | if (ret || (retlen != rawlen)) { | 638 | if (ret || (retlen != rawlen)) { |
626 | printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n", | 639 | printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n", |
627 | rawlen, phys_ofs, ret, retlen); | 640 | rawlen, phys_ofs, ret, retlen); |
628 | if (retlen) { | 641 | if (retlen) { |
629 | jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, rawlen, NULL); | 642 | jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, rawlen, NULL); |
630 | } else { | 643 | } else { |
diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h index b13298a824ed..3a2197f3c812 100644 --- a/fs/jffs2/jffs2_fs_sb.h +++ b/fs/jffs2/jffs2_fs_sb.h | |||
@@ -69,6 +69,8 @@ struct jffs2_sb_info { | |||
69 | uint8_t resv_blocks_gctrigger; /* ... wake up the GC thread */ | 69 | uint8_t resv_blocks_gctrigger; /* ... wake up the GC thread */ |
70 | uint8_t resv_blocks_gcbad; /* ... pick a block from the bad_list to GC */ | 70 | uint8_t resv_blocks_gcbad; /* ... pick a block from the bad_list to GC */ |
71 | uint8_t resv_blocks_gcmerge; /* ... merge pages when garbage collecting */ | 71 | uint8_t resv_blocks_gcmerge; /* ... merge pages when garbage collecting */ |
72 | /* Number of 'very dirty' blocks before we trigger immediate GC */ | ||
73 | uint8_t vdirty_blocks_gctrigger; | ||
72 | 74 | ||
73 | uint32_t nospc_dirty_size; | 75 | uint32_t nospc_dirty_size; |
74 | 76 | ||
@@ -106,6 +108,9 @@ struct jffs2_sb_info { | |||
106 | 108 | ||
107 | uint32_t wbuf_pagesize; /* 0 for NOR and other flashes with no wbuf */ | 109 | uint32_t wbuf_pagesize; /* 0 for NOR and other flashes with no wbuf */ |
108 | 110 | ||
111 | #ifdef CONFIG_JFFS2_FS_WBUF_VERIFY | ||
112 | unsigned char *wbuf_verify; /* read-back buffer for verification */ | ||
113 | #endif | ||
109 | #ifdef CONFIG_JFFS2_FS_WRITEBUFFER | 114 | #ifdef CONFIG_JFFS2_FS_WRITEBUFFER |
110 | unsigned char *wbuf; /* Write-behind buffer for NAND flash */ | 115 | unsigned char *wbuf; /* Write-behind buffer for NAND flash */ |
111 | uint32_t wbuf_ofs; | 116 | uint32_t wbuf_ofs; |
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index bc5509fe577b..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 */ |
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index dbc908ad622b..a0313fa8748e 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 |
@@ -717,6 +722,8 @@ int jffs2_thread_should_wake(struct jffs2_sb_info *c) | |||
717 | { | 722 | { |
718 | int ret = 0; | 723 | int ret = 0; |
719 | uint32_t dirty; | 724 | uint32_t dirty; |
725 | int nr_very_dirty = 0; | ||
726 | struct jffs2_eraseblock *jeb; | ||
720 | 727 | ||
721 | if (c->unchecked_size) { | 728 | if (c->unchecked_size) { |
722 | D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): unchecked_size %d, checked_ino #%d\n", | 729 | D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): unchecked_size %d, checked_ino #%d\n", |
@@ -738,8 +745,18 @@ int jffs2_thread_should_wake(struct jffs2_sb_info *c) | |||
738 | (dirty > c->nospc_dirty_size)) | 745 | (dirty > c->nospc_dirty_size)) |
739 | ret = 1; | 746 | ret = 1; |
740 | 747 | ||
741 | D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n", | 748 | list_for_each_entry(jeb, &c->very_dirty_list, list) { |
742 | c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, ret?"yes":"no")); | 749 | nr_very_dirty++; |
750 | if (nr_very_dirty == c->vdirty_blocks_gctrigger) { | ||
751 | ret = 1; | ||
752 | /* In debug mode, actually go through and count them all */ | ||
753 | D1(continue); | ||
754 | break; | ||
755 | } | ||
756 | } | ||
757 | |||
758 | D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x, vdirty_blocks %d: %s\n", | ||
759 | c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, nr_very_dirty, ret?"yes":"no")); | ||
743 | 760 | ||
744 | return ret; | 761 | return ret; |
745 | } | 762 | } |
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 80daea96bbc2..f6743a915cf3 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h | |||
@@ -173,12 +173,15 @@ int jffs2_ioctl(struct inode *, struct file *, unsigned int, unsigned long); | |||
173 | extern const struct inode_operations jffs2_symlink_inode_operations; | 173 | extern const struct inode_operations jffs2_symlink_inode_operations; |
174 | 174 | ||
175 | /* fs.c */ | 175 | /* fs.c */ |
176 | struct posix_acl; | ||
177 | |||
176 | int jffs2_setattr (struct dentry *, struct iattr *); | 178 | int jffs2_setattr (struct dentry *, struct iattr *); |
179 | int jffs2_do_setattr (struct inode *, struct iattr *); | ||
177 | void jffs2_read_inode (struct inode *); | 180 | void jffs2_read_inode (struct inode *); |
178 | void jffs2_clear_inode (struct inode *); | 181 | void jffs2_clear_inode (struct inode *); |
179 | void jffs2_dirty_inode(struct inode *inode); | 182 | void jffs2_dirty_inode(struct inode *inode); |
180 | struct inode *jffs2_new_inode (struct inode *dir_i, int mode, | 183 | struct inode *jffs2_new_inode (struct inode *dir_i, int mode, |
181 | struct jffs2_raw_inode *ri); | 184 | struct jffs2_raw_inode *ri, struct posix_acl **acl); |
182 | int jffs2_statfs (struct dentry *, struct kstatfs *); | 185 | int jffs2_statfs (struct dentry *, struct kstatfs *); |
183 | void jffs2_write_super (struct super_block *); | 186 | void jffs2_write_super (struct super_block *); |
184 | int jffs2_remount_fs (struct super_block *, int *, char *); | 187 | int jffs2_remount_fs (struct super_block *, int *, char *); |
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index b5baa356fed2..2eae5d2dbebe 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c | |||
@@ -65,7 +65,7 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info | |||
65 | err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer); | 65 | err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer); |
66 | if (!err && retlen < tn->csize) { | 66 | if (!err && retlen < tn->csize) { |
67 | JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize); | 67 | JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize); |
68 | c->mtd->unpoint(c->mtd, buffer, ofs, len); | 68 | c->mtd->unpoint(c->mtd, buffer, ofs, retlen); |
69 | } else if (err) | 69 | } else if (err) |
70 | JFFS2_WARNING("MTD point failed: error code %d.\n", err); | 70 | JFFS2_WARNING("MTD point failed: error code %d.\n", err); |
71 | else | 71 | else |
@@ -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, |
@@ -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 6c75cd433342..272872d27fd5 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c | |||
@@ -101,7 +101,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) | |||
101 | if (!ret && pointlen < c->mtd->size) { | 101 | if (!ret && pointlen < c->mtd->size) { |
102 | /* Don't muck about if it won't let us point to the whole flash */ | 102 | /* Don't muck about if it won't let us point to the whole flash */ |
103 | D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", pointlen)); | 103 | D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", pointlen)); |
104 | c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size); | 104 | c->mtd->unpoint(c->mtd, flashbuf, 0, pointlen); |
105 | flashbuf = NULL; | 105 | flashbuf = NULL; |
106 | } | 106 | } |
107 | if (ret) | 107 | if (ret) |
@@ -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))))) |
@@ -1004,6 +1004,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo | |||
1004 | { | 1004 | { |
1005 | struct jffs2_full_dirent *fd; | 1005 | struct jffs2_full_dirent *fd; |
1006 | struct jffs2_inode_cache *ic; | 1006 | struct jffs2_inode_cache *ic; |
1007 | uint32_t checkedlen; | ||
1007 | uint32_t crc; | 1008 | uint32_t crc; |
1008 | int err; | 1009 | int err; |
1009 | 1010 | ||
@@ -1024,12 +1025,18 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo | |||
1024 | 1025 | ||
1025 | pseudo_random += je32_to_cpu(rd->version); | 1026 | pseudo_random += je32_to_cpu(rd->version); |
1026 | 1027 | ||
1027 | fd = jffs2_alloc_full_dirent(rd->nsize+1); | 1028 | /* Should never happen. Did. (OLPC trac #4184)*/ |
1029 | checkedlen = strnlen(rd->name, rd->nsize); | ||
1030 | if (checkedlen < rd->nsize) { | ||
1031 | printk(KERN_ERR "Dirent at %08x has zeroes in name. Truncating to %d chars\n", | ||
1032 | ofs, checkedlen); | ||
1033 | } | ||
1034 | fd = jffs2_alloc_full_dirent(checkedlen+1); | ||
1028 | if (!fd) { | 1035 | if (!fd) { |
1029 | return -ENOMEM; | 1036 | return -ENOMEM; |
1030 | } | 1037 | } |
1031 | memcpy(&fd->name, rd->name, rd->nsize); | 1038 | memcpy(&fd->name, rd->name, checkedlen); |
1032 | fd->name[rd->nsize] = 0; | 1039 | fd->name[checkedlen] = 0; |
1033 | 1040 | ||
1034 | crc = crc32(0, fd->name, rd->nsize); | 1041 | crc = crc32(0, fd->name, rd->nsize); |
1035 | if (crc != je32_to_cpu(rd->name_crc)) { | 1042 | if (crc != je32_to_cpu(rd->name_crc)) { |
@@ -1055,7 +1062,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo | |||
1055 | fd->next = NULL; | 1062 | fd->next = NULL; |
1056 | fd->version = je32_to_cpu(rd->version); | 1063 | fd->version = je32_to_cpu(rd->version); |
1057 | fd->ino = je32_to_cpu(rd->ino); | 1064 | fd->ino = je32_to_cpu(rd->ino); |
1058 | fd->nhash = full_name_hash(fd->name, rd->nsize); | 1065 | fd->nhash = full_name_hash(fd->name, checkedlen); |
1059 | fd->type = rd->type; | 1066 | fd->type = rd->type; |
1060 | jffs2_add_fd_to_list(c, fd, &ic->scan_dents); | 1067 | jffs2_add_fd_to_list(c, fd, &ic->scan_dents); |
1061 | 1068 | ||
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..629af01e5ade 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 | * |
@@ -429,6 +429,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras | |||
429 | 429 | ||
430 | case JFFS2_NODETYPE_DIRENT: { | 430 | case JFFS2_NODETYPE_DIRENT: { |
431 | struct jffs2_sum_dirent_flash *spd; | 431 | struct jffs2_sum_dirent_flash *spd; |
432 | int checkedlen; | ||
432 | spd = sp; | 433 | spd = sp; |
433 | 434 | ||
434 | dbg_summary("Dirent at 0x%08x-0x%08x\n", | 435 | dbg_summary("Dirent at 0x%08x-0x%08x\n", |
@@ -436,12 +437,25 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras | |||
436 | jeb->offset + je32_to_cpu(spd->offset) + je32_to_cpu(spd->totlen)); | 437 | jeb->offset + je32_to_cpu(spd->offset) + je32_to_cpu(spd->totlen)); |
437 | 438 | ||
438 | 439 | ||
439 | fd = jffs2_alloc_full_dirent(spd->nsize+1); | 440 | /* This should never happen, but https://dev.laptop.org/ticket/4184 */ |
441 | checkedlen = strnlen(spd->name, spd->nsize); | ||
442 | if (!checkedlen) { | ||
443 | printk(KERN_ERR "Dirent at %08x has zero at start of name. Aborting mount.\n", | ||
444 | jeb->offset + je32_to_cpu(spd->offset)); | ||
445 | return -EIO; | ||
446 | } | ||
447 | if (checkedlen < spd->nsize) { | ||
448 | printk(KERN_ERR "Dirent at %08x has zeroes in name. Truncating to %d chars\n", | ||
449 | jeb->offset + je32_to_cpu(spd->offset), checkedlen); | ||
450 | } | ||
451 | |||
452 | |||
453 | fd = jffs2_alloc_full_dirent(checkedlen+1); | ||
440 | if (!fd) | 454 | if (!fd) |
441 | return -ENOMEM; | 455 | return -ENOMEM; |
442 | 456 | ||
443 | memcpy(&fd->name, spd->name, spd->nsize); | 457 | memcpy(&fd->name, spd->name, checkedlen); |
444 | fd->name[spd->nsize] = 0; | 458 | fd->name[checkedlen] = 0; |
445 | 459 | ||
446 | ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(spd->pino)); | 460 | ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(spd->pino)); |
447 | if (!ic) { | 461 | if (!ic) { |
@@ -455,7 +469,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras | |||
455 | fd->next = NULL; | 469 | fd->next = NULL; |
456 | fd->version = je32_to_cpu(spd->version); | 470 | fd->version = je32_to_cpu(spd->version); |
457 | fd->ino = je32_to_cpu(spd->ino); | 471 | fd->ino = je32_to_cpu(spd->ino); |
458 | fd->nhash = full_name_hash(fd->name, spd->nsize); | 472 | fd->nhash = full_name_hash(fd->name, checkedlen); |
459 | fd->type = spd->type; | 473 | fd->type = spd->type; |
460 | 474 | ||
461 | jffs2_add_fd_to_list(c, fd, &ic->scan_dents); | 475 | jffs2_add_fd_to_list(c, fd, &ic->scan_dents); |
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..d1d4f27464ba 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; |
@@ -966,8 +1008,8 @@ exit: | |||
966 | 1008 | ||
967 | #define NR_OOB_SCAN_PAGES 4 | 1009 | #define NR_OOB_SCAN_PAGES 4 |
968 | 1010 | ||
969 | /* For historical reasons we use only 12 bytes for OOB clean marker */ | 1011 | /* For historical reasons we use only 8 bytes for OOB clean marker */ |
970 | #define OOB_CM_SIZE 12 | 1012 | #define OOB_CM_SIZE 8 |
971 | 1013 | ||
972 | static const struct jffs2_unknown_node oob_cleanmarker = | 1014 | static const struct jffs2_unknown_node oob_cleanmarker = |
973 | { | 1015 | { |
@@ -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 664c164aa67c..2f5695446d0f 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c | |||
@@ -215,6 +215,17 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff | |||
215 | BUG(); | 215 | BUG(); |
216 | }); | 216 | }); |
217 | 217 | ||
218 | if (strnlen(name, namelen) != namelen) { | ||
219 | /* This should never happen, but seems to have done on at least one | ||
220 | occasion: https://dev.laptop.org/ticket/4184 */ | ||
221 | printk(KERN_CRIT "Error in jffs2_write_dirent() -- name contains zero bytes!\n"); | ||
222 | printk(KERN_CRIT "Directory inode #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x\n", | ||
223 | je32_to_cpu(rd->pino), name, name, je32_to_cpu(rd->ino), | ||
224 | je32_to_cpu(rd->name_crc)); | ||
225 | WARN_ON(1); | ||
226 | return ERR_PTR(-EIO); | ||
227 | } | ||
228 | |||
218 | vecs[0].iov_base = rd; | 229 | vecs[0].iov_base = rd; |
219 | vecs[0].iov_len = sizeof(*rd); | 230 | vecs[0].iov_len = sizeof(*rd); |
220 | vecs[1].iov_base = (unsigned char *)name; | 231 | vecs[1].iov_base = (unsigned char *)name; |
@@ -226,7 +237,7 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff | |||
226 | 237 | ||
227 | fd->version = je32_to_cpu(rd->version); | 238 | fd->version = je32_to_cpu(rd->version); |
228 | fd->ino = je32_to_cpu(rd->ino); | 239 | fd->ino = je32_to_cpu(rd->ino); |
229 | fd->nhash = full_name_hash(name, strlen(name)); | 240 | fd->nhash = full_name_hash(name, namelen); |
230 | fd->type = rd->type; | 241 | fd->type = rd->type; |
231 | memcpy(fd->name, name, namelen); | 242 | memcpy(fd->name, name, namelen); |
232 | fd->name[namelen]=0; | 243 | fd->name[namelen]=0; |
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; |