diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/Kconfig | 26 | ||||
-rw-r--r-- | fs/jffs2/Makefile | 5 | ||||
-rw-r--r-- | fs/jffs2/README.Locking | 6 | ||||
-rw-r--r-- | fs/jffs2/background.c | 13 | ||||
-rw-r--r-- | fs/jffs2/build.c | 9 | ||||
-rw-r--r-- | fs/jffs2/compr_zlib.c | 4 | ||||
-rw-r--r-- | fs/jffs2/dir.c | 28 | ||||
-rw-r--r-- | fs/jffs2/erase.c | 24 | ||||
-rw-r--r-- | fs/jffs2/fs.c | 21 | ||||
-rw-r--r-- | fs/jffs2/gc.c | 41 | ||||
-rw-r--r-- | fs/jffs2/nodelist.c | 23 | ||||
-rw-r--r-- | fs/jffs2/nodelist.h | 17 | ||||
-rw-r--r-- | fs/jffs2/nodemgmt.c | 31 | ||||
-rw-r--r-- | fs/jffs2/os-linux.h | 24 | ||||
-rw-r--r-- | fs/jffs2/read.c | 32 | ||||
-rw-r--r-- | fs/jffs2/readinode.c | 62 | ||||
-rw-r--r-- | fs/jffs2/scan.c | 39 | ||||
-rw-r--r-- | fs/jffs2/super.c | 8 | ||||
-rw-r--r-- | fs/jffs2/symlink.c | 42 | ||||
-rw-r--r-- | fs/jffs2/wbuf.c | 164 | ||||
-rw-r--r-- | fs/jffs2/write.c | 55 |
21 files changed, 444 insertions, 230 deletions
diff --git a/fs/Kconfig b/fs/Kconfig index 062177956239..8d50a610c0e0 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
@@ -1036,26 +1036,18 @@ config JFFS2_FS_DEBUG | |||
1036 | If reporting bugs, please try to have available a full dump of the | 1036 | If reporting bugs, please try to have available a full dump of the |
1037 | messages at debug level 1 while the misbehaviour was occurring. | 1037 | messages at debug level 1 while the misbehaviour was occurring. |
1038 | 1038 | ||
1039 | config JFFS2_FS_NAND | 1039 | config JFFS2_FS_WRITEBUFFER |
1040 | bool "JFFS2 support for NAND flash" | 1040 | bool "JFFS2 write-buffering support" |
1041 | depends on JFFS2_FS | 1041 | depends on JFFS2_FS |
1042 | default n | 1042 | default y |
1043 | help | 1043 | help |
1044 | This enables the support for NAND flash in JFFS2. NAND is a newer | 1044 | This enables the write-buffering support in JFFS2. |
1045 | type of flash chip design than the traditional NOR flash, with | ||
1046 | higher density but a handful of characteristics which make it more | ||
1047 | interesting for the file system to use. | ||
1048 | 1045 | ||
1049 | Say 'N' unless you have NAND flash. | 1046 | This functionality is required to support JFFS2 on the following |
1050 | 1047 | types of flash devices: | |
1051 | config JFFS2_FS_NOR_ECC | 1048 | - NAND flash |
1052 | bool "JFFS2 support for ECC'd NOR flash (EXPERIMENTAL)" | 1049 | - NOR flash with transparent ECC |
1053 | depends on JFFS2_FS && EXPERIMENTAL | 1050 | - DataFlash |
1054 | default n | ||
1055 | help | ||
1056 | This enables the experimental support for NOR flash with transparent | ||
1057 | ECC for JFFS2. This type of flash chip is not common, however it is | ||
1058 | available from ST Microelectronics. | ||
1059 | 1051 | ||
1060 | config JFFS2_COMPRESSION_OPTIONS | 1052 | config JFFS2_COMPRESSION_OPTIONS |
1061 | bool "Advanced compression options for JFFS2" | 1053 | bool "Advanced compression options for JFFS2" |
diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile index e3c38ccf9c7d..f1afe681ecd6 100644 --- a/fs/jffs2/Makefile +++ b/fs/jffs2/Makefile | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Makefile for the Linux Journalling Flash File System v2 (JFFS2) | 2 | # Makefile for the Linux Journalling Flash File System v2 (JFFS2) |
3 | # | 3 | # |
4 | # $Id: Makefile.common,v 1.7 2004/11/03 12:57:38 jwboyer Exp $ | 4 | # $Id: Makefile.common,v 1.9 2005/02/09 09:23:53 pavlov Exp $ |
5 | # | 5 | # |
6 | 6 | ||
7 | obj-$(CONFIG_JFFS2_FS) += jffs2.o | 7 | obj-$(CONFIG_JFFS2_FS) += jffs2.o |
@@ -11,8 +11,7 @@ jffs2-y += read.o nodemgmt.o readinode.o write.o scan.o gc.o | |||
11 | jffs2-y += symlink.o build.o erase.o background.o fs.o writev.o | 11 | jffs2-y += symlink.o build.o erase.o background.o fs.o writev.o |
12 | jffs2-y += super.o | 12 | jffs2-y += super.o |
13 | 13 | ||
14 | jffs2-$(CONFIG_JFFS2_FS_NAND) += wbuf.o | 14 | jffs2-$(CONFIG_JFFS2_FS_WRITEBUFFER) += wbuf.o |
15 | jffs2-$(CONFIG_JFFS2_FS_NOR_ECC) += wbuf.o | ||
16 | jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o | 15 | jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o |
17 | jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o | 16 | jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o |
18 | jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o | 17 | jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o |
diff --git a/fs/jffs2/README.Locking b/fs/jffs2/README.Locking index 49771cf8513a..b7943439b6ec 100644 --- a/fs/jffs2/README.Locking +++ b/fs/jffs2/README.Locking | |||
@@ -1,4 +1,4 @@ | |||
1 | $Id: README.Locking,v 1.9 2004/11/20 10:35:40 dwmw2 Exp $ | 1 | $Id: README.Locking,v 1.12 2005/04/13 13:22:35 dwmw2 Exp $ |
2 | 2 | ||
3 | JFFS2 LOCKING DOCUMENTATION | 3 | JFFS2 LOCKING DOCUMENTATION |
4 | --------------------------- | 4 | --------------------------- |
@@ -108,6 +108,10 @@ in-core jffs2_inode_cache objects (each inode in JFFS2 has the | |||
108 | correspondent jffs2_inode_cache object). So, the inocache_lock | 108 | correspondent jffs2_inode_cache object). So, the inocache_lock |
109 | has to be locked while walking the c->inocache_list hash buckets. | 109 | has to be locked while walking the c->inocache_list hash buckets. |
110 | 110 | ||
111 | This spinlock also covers allocation of new inode numbers, which is | ||
112 | currently just '++->highest_ino++', but might one day get more complicated | ||
113 | if we need to deal with wrapping after 4 milliard inode numbers are used. | ||
114 | |||
111 | Note, the f->sem guarantees that the correspondent jffs2_inode_cache | 115 | Note, the f->sem guarantees that the correspondent jffs2_inode_cache |
112 | will not be removed. So, it is allowed to access it without locking | 116 | will not be removed. So, it is allowed to access it without locking |
113 | the inocache_lock spinlock. | 117 | the inocache_lock spinlock. |
diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index 638836b277d4..0f224384f176 100644 --- a/fs/jffs2/background.c +++ b/fs/jffs2/background.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: background.c,v 1.50 2004/11/16 20:36:10 dwmw2 Exp $ | 10 | * $Id: background.c,v 1.54 2005/05/20 21:37:12 gleixner Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -37,7 +37,7 @@ int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c) | |||
37 | if (c->gc_task) | 37 | if (c->gc_task) |
38 | BUG(); | 38 | BUG(); |
39 | 39 | ||
40 | init_MUTEX_LOCKED(&c->gc_thread_start); | 40 | init_completion(&c->gc_thread_start); |
41 | init_completion(&c->gc_thread_exit); | 41 | init_completion(&c->gc_thread_exit); |
42 | 42 | ||
43 | pid = kernel_thread(jffs2_garbage_collect_thread, c, CLONE_FS|CLONE_FILES); | 43 | pid = kernel_thread(jffs2_garbage_collect_thread, c, CLONE_FS|CLONE_FILES); |
@@ -48,7 +48,7 @@ int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c) | |||
48 | } else { | 48 | } else { |
49 | /* Wait for it... */ | 49 | /* Wait for it... */ |
50 | D1(printk(KERN_DEBUG "JFFS2: Garbage collect thread is pid %d\n", pid)); | 50 | D1(printk(KERN_DEBUG "JFFS2: Garbage collect thread is pid %d\n", pid)); |
51 | down(&c->gc_thread_start); | 51 | wait_for_completion(&c->gc_thread_start); |
52 | } | 52 | } |
53 | 53 | ||
54 | return ret; | 54 | return ret; |
@@ -56,13 +56,16 @@ int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c) | |||
56 | 56 | ||
57 | void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c) | 57 | void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c) |
58 | { | 58 | { |
59 | int wait = 0; | ||
59 | spin_lock(&c->erase_completion_lock); | 60 | spin_lock(&c->erase_completion_lock); |
60 | if (c->gc_task) { | 61 | if (c->gc_task) { |
61 | D1(printk(KERN_DEBUG "jffs2: Killing GC task %d\n", c->gc_task->pid)); | 62 | D1(printk(KERN_DEBUG "jffs2: Killing GC task %d\n", c->gc_task->pid)); |
62 | send_sig(SIGKILL, c->gc_task, 1); | 63 | send_sig(SIGKILL, c->gc_task, 1); |
64 | wait = 1; | ||
63 | } | 65 | } |
64 | spin_unlock(&c->erase_completion_lock); | 66 | spin_unlock(&c->erase_completion_lock); |
65 | wait_for_completion(&c->gc_thread_exit); | 67 | if (wait) |
68 | wait_for_completion(&c->gc_thread_exit); | ||
66 | } | 69 | } |
67 | 70 | ||
68 | static int jffs2_garbage_collect_thread(void *_c) | 71 | static int jffs2_garbage_collect_thread(void *_c) |
@@ -75,7 +78,7 @@ static int jffs2_garbage_collect_thread(void *_c) | |||
75 | allow_signal(SIGCONT); | 78 | allow_signal(SIGCONT); |
76 | 79 | ||
77 | c->gc_task = current; | 80 | c->gc_task = current; |
78 | up(&c->gc_thread_start); | 81 | complete(&c->gc_thread_start); |
79 | 82 | ||
80 | set_user_nice(current, 10); | 83 | set_user_nice(current, 10); |
81 | 84 | ||
diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c index a01dd5fdbb95..3dd5394921c9 100644 --- a/fs/jffs2/build.c +++ b/fs/jffs2/build.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: build.c,v 1.69 2004/12/16 20:22:18 dmarlin Exp $ | 10 | * $Id: build.c,v 1.70 2005/02/28 08:21:05 dedekind Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -97,14 +97,16 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) | |||
97 | /* First, scan the medium and build all the inode caches with | 97 | /* First, scan the medium and build all the inode caches with |
98 | lists of physical nodes */ | 98 | lists of physical nodes */ |
99 | 99 | ||
100 | c->flags |= JFFS2_SB_FLAG_MOUNTING; | 100 | c->flags |= JFFS2_SB_FLAG_SCANNING; |
101 | ret = jffs2_scan_medium(c); | 101 | ret = jffs2_scan_medium(c); |
102 | c->flags &= ~JFFS2_SB_FLAG_SCANNING; | ||
102 | if (ret) | 103 | if (ret) |
103 | goto exit; | 104 | goto exit; |
104 | 105 | ||
105 | D1(printk(KERN_DEBUG "Scanned flash completely\n")); | 106 | D1(printk(KERN_DEBUG "Scanned flash completely\n")); |
106 | D2(jffs2_dump_block_lists(c)); | 107 | D2(jffs2_dump_block_lists(c)); |
107 | 108 | ||
109 | c->flags |= JFFS2_SB_FLAG_BUILDING; | ||
108 | /* Now scan the directory tree, increasing nlink according to every dirent found. */ | 110 | /* Now scan the directory tree, increasing nlink according to every dirent found. */ |
109 | for_each_inode(i, c, ic) { | 111 | for_each_inode(i, c, ic) { |
110 | D1(printk(KERN_DEBUG "Pass 1: ino #%u\n", ic->ino)); | 112 | D1(printk(KERN_DEBUG "Pass 1: ino #%u\n", ic->ino)); |
@@ -116,7 +118,6 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) | |||
116 | cond_resched(); | 118 | cond_resched(); |
117 | } | 119 | } |
118 | } | 120 | } |
119 | c->flags &= ~JFFS2_SB_FLAG_MOUNTING; | ||
120 | 121 | ||
121 | D1(printk(KERN_DEBUG "Pass 1 complete\n")); | 122 | D1(printk(KERN_DEBUG "Pass 1 complete\n")); |
122 | 123 | ||
@@ -164,6 +165,8 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) | |||
164 | ic->scan_dents = NULL; | 165 | ic->scan_dents = NULL; |
165 | cond_resched(); | 166 | cond_resched(); |
166 | } | 167 | } |
168 | c->flags &= ~JFFS2_SB_FLAG_BUILDING; | ||
169 | |||
167 | D1(printk(KERN_DEBUG "Pass 3 complete\n")); | 170 | D1(printk(KERN_DEBUG "Pass 3 complete\n")); |
168 | D2(jffs2_dump_block_lists(c)); | 171 | D2(jffs2_dump_block_lists(c)); |
169 | 172 | ||
diff --git a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c index 078a30e406b5..83f7e0788fd0 100644 --- a/fs/jffs2/compr_zlib.c +++ b/fs/jffs2/compr_zlib.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: compr_zlib.c,v 1.29 2004/11/16 20:36:11 dwmw2 Exp $ | 10 | * $Id: compr_zlib.c,v 1.31 2005/05/20 19:30:06 gleixner Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -17,10 +17,10 @@ | |||
17 | 17 | ||
18 | #include <linux/config.h> | 18 | #include <linux/config.h> |
19 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
20 | #include <linux/sched.h> | ||
20 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
21 | #include <linux/zlib.h> | 22 | #include <linux/zlib.h> |
22 | #include <linux/zutil.h> | 23 | #include <linux/zutil.h> |
23 | #include <asm/semaphore.h> | ||
24 | #include "nodelist.h" | 24 | #include "nodelist.h" |
25 | #include "compr.h" | 25 | #include "compr.h" |
26 | 26 | ||
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index 757306fa3ff4..6421be874ce3 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: dir.c,v 1.84 2004/11/16 20:36:11 dwmw2 Exp $ | 10 | * $Id: dir.c,v 1.85 2005/03/01 10:34:03 dedekind Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -296,11 +296,11 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
296 | struct jffs2_full_dirent *fd; | 296 | struct jffs2_full_dirent *fd; |
297 | int namelen; | 297 | int namelen; |
298 | uint32_t alloclen, phys_ofs; | 298 | uint32_t alloclen, phys_ofs; |
299 | int ret; | 299 | int ret, targetlen = strlen(target); |
300 | 300 | ||
301 | /* FIXME: If you care. We'd need to use frags for the target | 301 | /* FIXME: If you care. We'd need to use frags for the target |
302 | if it grows much more than this */ | 302 | if it grows much more than this */ |
303 | if (strlen(target) > 254) | 303 | if (targetlen > 254) |
304 | return -EINVAL; | 304 | return -EINVAL; |
305 | 305 | ||
306 | ri = jffs2_alloc_raw_inode(); | 306 | ri = jffs2_alloc_raw_inode(); |
@@ -314,7 +314,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
314 | * Just the node will do for now, though | 314 | * Just the node will do for now, though |
315 | */ | 315 | */ |
316 | namelen = dentry->d_name.len; | 316 | namelen = dentry->d_name.len; |
317 | ret = jffs2_reserve_space(c, sizeof(*ri) + strlen(target), &phys_ofs, &alloclen, ALLOC_NORMAL); | 317 | ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &phys_ofs, &alloclen, ALLOC_NORMAL); |
318 | 318 | ||
319 | if (ret) { | 319 | if (ret) { |
320 | jffs2_free_raw_inode(ri); | 320 | jffs2_free_raw_inode(ri); |
@@ -333,16 +333,16 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
333 | 333 | ||
334 | f = JFFS2_INODE_INFO(inode); | 334 | f = JFFS2_INODE_INFO(inode); |
335 | 335 | ||
336 | inode->i_size = strlen(target); | 336 | inode->i_size = targetlen; |
337 | ri->isize = ri->dsize = ri->csize = cpu_to_je32(inode->i_size); | 337 | ri->isize = ri->dsize = ri->csize = cpu_to_je32(inode->i_size); |
338 | ri->totlen = cpu_to_je32(sizeof(*ri) + inode->i_size); | 338 | ri->totlen = cpu_to_je32(sizeof(*ri) + inode->i_size); |
339 | ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); | 339 | ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); |
340 | 340 | ||
341 | ri->compr = JFFS2_COMPR_NONE; | 341 | ri->compr = JFFS2_COMPR_NONE; |
342 | ri->data_crc = cpu_to_je32(crc32(0, target, strlen(target))); | 342 | ri->data_crc = cpu_to_je32(crc32(0, target, targetlen)); |
343 | ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); | 343 | ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); |
344 | 344 | ||
345 | fn = jffs2_write_dnode(c, f, ri, target, strlen(target), phys_ofs, ALLOC_NORMAL); | 345 | fn = jffs2_write_dnode(c, f, ri, target, targetlen, phys_ofs, ALLOC_NORMAL); |
346 | 346 | ||
347 | jffs2_free_raw_inode(ri); | 347 | jffs2_free_raw_inode(ri); |
348 | 348 | ||
@@ -353,6 +353,20 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
353 | jffs2_clear_inode(inode); | 353 | jffs2_clear_inode(inode); |
354 | return PTR_ERR(fn); | 354 | return PTR_ERR(fn); |
355 | } | 355 | } |
356 | |||
357 | /* We use f->dents field to store the target path. */ | ||
358 | f->dents = kmalloc(targetlen + 1, GFP_KERNEL); | ||
359 | if (!f->dents) { | ||
360 | printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1); | ||
361 | up(&f->sem); | ||
362 | jffs2_complete_reservation(c); | ||
363 | jffs2_clear_inode(inode); | ||
364 | return -ENOMEM; | ||
365 | } | ||
366 | |||
367 | memcpy(f->dents, target, targetlen + 1); | ||
368 | D1(printk(KERN_DEBUG "jffs2_symlink: symlink's target '%s' cached\n", (char *)f->dents)); | ||
369 | |||
356 | /* No data here. Only a metadata node, which will be | 370 | /* No data here. Only a metadata node, which will be |
357 | obsoleted by the first data write | 371 | obsoleted by the first data write |
358 | */ | 372 | */ |
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index 41451e8bf361..6a4c0a3685da 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: erase.c,v 1.66 2004/11/16 20:36:11 dwmw2 Exp $ | 10 | * $Id: erase.c,v 1.76 2005/05/03 15:11:40 dedekind Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -48,6 +48,7 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, | |||
48 | #else /* Linux */ | 48 | #else /* Linux */ |
49 | struct erase_info *instr; | 49 | struct erase_info *instr; |
50 | 50 | ||
51 | D1(printk(KERN_DEBUG "jffs2_erase_block(): erase block %#x (range %#x-%#x)\n", jeb->offset, jeb->offset, jeb->offset + c->sector_size)); | ||
51 | instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL); | 52 | instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL); |
52 | if (!instr) { | 53 | if (!instr) { |
53 | printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n"); | 54 | printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n"); |
@@ -233,7 +234,7 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c, | |||
233 | continue; | 234 | continue; |
234 | } | 235 | } |
235 | 236 | ||
236 | if (((*prev)->flash_offset & ~(c->sector_size -1)) == jeb->offset) { | 237 | if (SECTOR_ADDR((*prev)->flash_offset) == jeb->offset) { |
237 | /* It's in the block we're erasing */ | 238 | /* It's in the block we're erasing */ |
238 | struct jffs2_raw_node_ref *this; | 239 | struct jffs2_raw_node_ref *this; |
239 | 240 | ||
@@ -277,11 +278,8 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c, | |||
277 | printk("\n"); | 278 | printk("\n"); |
278 | }); | 279 | }); |
279 | 280 | ||
280 | if (ic->nodes == (void *)ic) { | 281 | if (ic->nodes == (void *)ic && ic->nlink == 0) |
281 | D1(printk(KERN_DEBUG "inocache for ino #%u is all gone now. Freeing\n", ic->ino)); | ||
282 | jffs2_del_ino_cache(c, ic); | 282 | jffs2_del_ino_cache(c, ic); |
283 | jffs2_free_inode_cache(ic); | ||
284 | } | ||
285 | } | 283 | } |
286 | 284 | ||
287 | static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) | 285 | static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) |
@@ -310,7 +308,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb | |||
310 | int ret; | 308 | int ret; |
311 | uint32_t bad_offset; | 309 | uint32_t bad_offset; |
312 | 310 | ||
313 | if (!jffs2_cleanmarker_oob(c)) { | 311 | if ((!jffs2_cleanmarker_oob(c)) && (c->cleanmarker_size > 0)) { |
314 | marker_ref = jffs2_alloc_raw_node_ref(); | 312 | marker_ref = jffs2_alloc_raw_node_ref(); |
315 | if (!marker_ref) { | 313 | if (!marker_ref) { |
316 | printk(KERN_WARNING "Failed to allocate raw node ref for clean marker\n"); | 314 | printk(KERN_WARNING "Failed to allocate raw node ref for clean marker\n"); |
@@ -335,7 +333,8 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb | |||
335 | 333 | ||
336 | bad_offset = ofs; | 334 | bad_offset = ofs; |
337 | 335 | ||
338 | ret = jffs2_flash_read(c, ofs, readlen, &retlen, ebuf); | 336 | ret = c->mtd->read(c->mtd, ofs, readlen, &retlen, ebuf); |
337 | |||
339 | if (ret) { | 338 | if (ret) { |
340 | printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret); | 339 | printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret); |
341 | goto bad; | 340 | goto bad; |
@@ -351,7 +350,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb | |||
351 | bad_offset += i; | 350 | bad_offset += i; |
352 | printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, bad_offset); | 351 | printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, bad_offset); |
353 | bad: | 352 | bad: |
354 | if (!jffs2_cleanmarker_oob(c)) | 353 | if ((!jffs2_cleanmarker_oob(c)) && (c->cleanmarker_size > 0)) |
355 | jffs2_free_raw_node_ref(marker_ref); | 354 | jffs2_free_raw_node_ref(marker_ref); |
356 | kfree(ebuf); | 355 | kfree(ebuf); |
357 | bad2: | 356 | bad2: |
@@ -387,6 +386,13 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb | |||
387 | jeb->used_size = 0; | 386 | jeb->used_size = 0; |
388 | jeb->dirty_size = 0; | 387 | jeb->dirty_size = 0; |
389 | jeb->wasted_size = 0; | 388 | jeb->wasted_size = 0; |
389 | } else if (c->cleanmarker_size == 0) { | ||
390 | jeb->first_node = jeb->last_node = NULL; | ||
391 | |||
392 | jeb->free_size = c->sector_size; | ||
393 | jeb->used_size = 0; | ||
394 | jeb->dirty_size = 0; | ||
395 | jeb->wasted_size = 0; | ||
390 | } else { | 396 | } else { |
391 | struct kvec vecs[1]; | 397 | struct kvec vecs[1]; |
392 | struct jffs2_unknown_node marker = { | 398 | struct jffs2_unknown_node marker = { |
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 30ab233fe423..c91c66e5e869 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: fs.c,v 1.51 2004/11/28 12:19:37 dedekind Exp $ | 10 | * $Id: fs.c,v 1.53 2005/02/09 09:23:53 pavlov Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -450,11 +450,15 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) | |||
450 | 450 | ||
451 | c = JFFS2_SB_INFO(sb); | 451 | c = JFFS2_SB_INFO(sb); |
452 | 452 | ||
453 | #ifndef CONFIG_JFFS2_FS_NAND | 453 | #ifndef CONFIG_JFFS2_FS_WRITEBUFFER |
454 | if (c->mtd->type == MTD_NANDFLASH) { | 454 | if (c->mtd->type == MTD_NANDFLASH) { |
455 | printk(KERN_ERR "jffs2: Cannot operate on NAND flash unless jffs2 NAND support is compiled in.\n"); | 455 | printk(KERN_ERR "jffs2: Cannot operate on NAND flash unless jffs2 NAND support is compiled in.\n"); |
456 | return -EINVAL; | 456 | return -EINVAL; |
457 | } | 457 | } |
458 | if (c->mtd->type == MTD_DATAFLASH) { | ||
459 | printk(KERN_ERR "jffs2: Cannot operate on DataFlash unless jffs2 DataFlash support is compiled in.\n"); | ||
460 | return -EINVAL; | ||
461 | } | ||
458 | #endif | 462 | #endif |
459 | 463 | ||
460 | c->flash_size = c->mtd->size; | 464 | c->flash_size = c->mtd->size; |
@@ -661,6 +665,14 @@ static int jffs2_flash_setup(struct jffs2_sb_info *c) { | |||
661 | if (ret) | 665 | if (ret) |
662 | return ret; | 666 | return ret; |
663 | } | 667 | } |
668 | |||
669 | /* and Dataflash */ | ||
670 | if (jffs2_dataflash(c)) { | ||
671 | ret = jffs2_dataflash_setup(c); | ||
672 | if (ret) | ||
673 | return ret; | ||
674 | } | ||
675 | |||
664 | return ret; | 676 | return ret; |
665 | } | 677 | } |
666 | 678 | ||
@@ -674,4 +686,9 @@ void jffs2_flash_cleanup(struct jffs2_sb_info *c) { | |||
674 | if (jffs2_nor_ecc(c)) { | 686 | if (jffs2_nor_ecc(c)) { |
675 | jffs2_nor_ecc_flash_cleanup(c); | 687 | jffs2_nor_ecc_flash_cleanup(c); |
676 | } | 688 | } |
689 | |||
690 | /* and DataFlash */ | ||
691 | if (jffs2_dataflash(c)) { | ||
692 | jffs2_dataflash_cleanup(c); | ||
693 | } | ||
677 | } | 694 | } |
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 87ec74ff5930..7086cd634503 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: gc.c,v 1.144 2004/12/21 11:18:50 dwmw2 Exp $ | 10 | * $Id: gc.c,v 1.148 2005/04/09 10:47:00 dedekind Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -50,6 +50,7 @@ static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c) | |||
50 | put the clever wear-levelling algorithms. Eventually. */ | 50 | put the clever wear-levelling algorithms. Eventually. */ |
51 | /* We possibly want to favour the dirtier blocks more when the | 51 | /* We possibly want to favour the dirtier blocks more when the |
52 | number of free blocks is low. */ | 52 | number of free blocks is low. */ |
53 | again: | ||
53 | if (!list_empty(&c->bad_used_list) && c->nr_free_blocks > c->resv_blocks_gcbad) { | 54 | if (!list_empty(&c->bad_used_list) && c->nr_free_blocks > c->resv_blocks_gcbad) { |
54 | D1(printk(KERN_DEBUG "Picking block from bad_used_list to GC next\n")); | 55 | D1(printk(KERN_DEBUG "Picking block from bad_used_list to GC next\n")); |
55 | nextlist = &c->bad_used_list; | 56 | nextlist = &c->bad_used_list; |
@@ -79,6 +80,13 @@ static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c) | |||
79 | D1(printk(KERN_DEBUG "Picking block from erasable_list to GC next (clean_list and {very_,}dirty_list were empty)\n")); | 80 | D1(printk(KERN_DEBUG "Picking block from erasable_list to GC next (clean_list and {very_,}dirty_list were empty)\n")); |
80 | 81 | ||
81 | nextlist = &c->erasable_list; | 82 | nextlist = &c->erasable_list; |
83 | } else if (!list_empty(&c->erasable_pending_wbuf_list)) { | ||
84 | /* There are blocks are wating for the wbuf sync */ | ||
85 | D1(printk(KERN_DEBUG "Synching wbuf in order to reuse erasable_pending_wbuf_list blocks\n")); | ||
86 | spin_unlock(&c->erase_completion_lock); | ||
87 | jffs2_flush_wbuf_pad(c); | ||
88 | spin_lock(&c->erase_completion_lock); | ||
89 | goto again; | ||
82 | } else { | 90 | } else { |
83 | /* Eep. All were empty */ | 91 | /* Eep. All were empty */ |
84 | D1(printk(KERN_NOTICE "jffs2: No clean, dirty _or_ erasable blocks to GC from! Where are they all?\n")); | 92 | D1(printk(KERN_NOTICE "jffs2: No clean, dirty _or_ erasable blocks to GC from! Where are they all?\n")); |
@@ -661,9 +669,10 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ | |||
661 | { | 669 | { |
662 | struct jffs2_full_dnode *new_fn; | 670 | struct jffs2_full_dnode *new_fn; |
663 | struct jffs2_raw_inode ri; | 671 | struct jffs2_raw_inode ri; |
672 | struct jffs2_node_frag *last_frag; | ||
664 | jint16_t dev; | 673 | jint16_t dev; |
665 | char *mdata = NULL, mdatalen = 0; | 674 | char *mdata = NULL, mdatalen = 0; |
666 | uint32_t alloclen, phys_ofs; | 675 | uint32_t alloclen, phys_ofs, ilen; |
667 | int ret; | 676 | int ret; |
668 | 677 | ||
669 | if (S_ISBLK(JFFS2_F_I_MODE(f)) || | 678 | if (S_ISBLK(JFFS2_F_I_MODE(f)) || |
@@ -699,6 +708,14 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ | |||
699 | goto out; | 708 | goto out; |
700 | } | 709 | } |
701 | 710 | ||
711 | last_frag = frag_last(&f->fragtree); | ||
712 | if (last_frag) | ||
713 | /* Fetch the inode length from the fragtree rather then | ||
714 | * from i_size since i_size may have not been updated yet */ | ||
715 | ilen = last_frag->ofs + last_frag->size; | ||
716 | else | ||
717 | ilen = JFFS2_F_I_SIZE(f); | ||
718 | |||
702 | memset(&ri, 0, sizeof(ri)); | 719 | memset(&ri, 0, sizeof(ri)); |
703 | ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | 720 | ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
704 | ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); | 721 | ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); |
@@ -710,7 +727,7 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ | |||
710 | ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); | 727 | ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); |
711 | ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); | 728 | ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); |
712 | ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); | 729 | ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); |
713 | ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f)); | 730 | ri.isize = cpu_to_je32(ilen); |
714 | ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f)); | 731 | ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f)); |
715 | ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f)); | 732 | ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f)); |
716 | ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f)); | 733 | ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f)); |
@@ -816,8 +833,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct | |||
816 | 833 | ||
817 | /* Doesn't matter if there's one in the same erase block. We're going to | 834 | /* Doesn't matter if there's one in the same erase block. We're going to |
818 | delete it too at the same time. */ | 835 | delete it too at the same time. */ |
819 | if ((raw->flash_offset & ~(c->sector_size-1)) == | 836 | if (SECTOR_ADDR(raw->flash_offset) == SECTOR_ADDR(fd->raw->flash_offset)) |
820 | (fd->raw->flash_offset & ~(c->sector_size-1))) | ||
821 | continue; | 837 | continue; |
822 | 838 | ||
823 | D1(printk(KERN_DEBUG "Check potential deletion dirent at %08x\n", ref_offset(raw))); | 839 | D1(printk(KERN_DEBUG "Check potential deletion dirent at %08x\n", ref_offset(raw))); |
@@ -891,7 +907,7 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras | |||
891 | struct jffs2_raw_inode ri; | 907 | struct jffs2_raw_inode ri; |
892 | struct jffs2_node_frag *frag; | 908 | struct jffs2_node_frag *frag; |
893 | struct jffs2_full_dnode *new_fn; | 909 | struct jffs2_full_dnode *new_fn; |
894 | uint32_t alloclen, phys_ofs; | 910 | uint32_t alloclen, phys_ofs, ilen; |
895 | int ret; | 911 | int ret; |
896 | 912 | ||
897 | D1(printk(KERN_DEBUG "Writing replacement hole node for ino #%u from offset 0x%x to 0x%x\n", | 913 | D1(printk(KERN_DEBUG "Writing replacement hole node for ino #%u from offset 0x%x to 0x%x\n", |
@@ -951,10 +967,19 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras | |||
951 | ri.csize = cpu_to_je32(0); | 967 | ri.csize = cpu_to_je32(0); |
952 | ri.compr = JFFS2_COMPR_ZERO; | 968 | ri.compr = JFFS2_COMPR_ZERO; |
953 | } | 969 | } |
970 | |||
971 | frag = frag_last(&f->fragtree); | ||
972 | if (frag) | ||
973 | /* Fetch the inode length from the fragtree rather then | ||
974 | * from i_size since i_size may have not been updated yet */ | ||
975 | ilen = frag->ofs + frag->size; | ||
976 | else | ||
977 | ilen = JFFS2_F_I_SIZE(f); | ||
978 | |||
954 | ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); | 979 | ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); |
955 | ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); | 980 | ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); |
956 | ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); | 981 | ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); |
957 | ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f)); | 982 | ri.isize = cpu_to_je32(ilen); |
958 | ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f)); | 983 | ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f)); |
959 | ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f)); | 984 | ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f)); |
960 | ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f)); | 985 | ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f)); |
@@ -1161,7 +1186,7 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era | |||
1161 | D1(printk(KERN_DEBUG "Expanded dnode to write from (0x%x-0x%x) to (0x%x-0x%x)\n", | 1186 | D1(printk(KERN_DEBUG "Expanded dnode to write from (0x%x-0x%x) to (0x%x-0x%x)\n", |
1162 | orig_start, orig_end, start, end)); | 1187 | orig_start, orig_end, start, end)); |
1163 | 1188 | ||
1164 | BUG_ON(end > JFFS2_F_I_SIZE(f)); | 1189 | D1(BUG_ON(end > frag_last(&f->fragtree)->ofs + frag_last(&f->fragtree)->size)); |
1165 | BUG_ON(end < orig_end); | 1190 | BUG_ON(end < orig_end); |
1166 | BUG_ON(start > orig_start); | 1191 | BUG_ON(start > orig_start); |
1167 | } | 1192 | } |
diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index cd6a8bd13e0b..8a8e4b863824 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: nodelist.c,v 1.90 2004/12/08 17:59:20 dwmw2 Exp $ | 10 | * $Id: nodelist.c,v 1.94 2005/04/13 13:22:35 dwmw2 Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -127,7 +127,7 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
127 | 127 | ||
128 | valid_ref = jffs2_first_valid_node(f->inocache->nodes); | 128 | valid_ref = jffs2_first_valid_node(f->inocache->nodes); |
129 | 129 | ||
130 | if (!valid_ref) | 130 | if (!valid_ref && (f->inocache->ino != 1)) |
131 | printk(KERN_WARNING "Eep. No valid nodes for ino #%u\n", f->inocache->ino); | 131 | printk(KERN_WARNING "Eep. No valid nodes for ino #%u\n", f->inocache->ino); |
132 | 132 | ||
133 | while (valid_ref) { | 133 | while (valid_ref) { |
@@ -489,9 +489,13 @@ struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t | |||
489 | void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new) | 489 | void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new) |
490 | { | 490 | { |
491 | struct jffs2_inode_cache **prev; | 491 | struct jffs2_inode_cache **prev; |
492 | D2(printk(KERN_DEBUG "jffs2_add_ino_cache: Add %p (ino #%u)\n", new, new->ino)); | 492 | |
493 | spin_lock(&c->inocache_lock); | 493 | spin_lock(&c->inocache_lock); |
494 | 494 | if (!new->ino) | |
495 | new->ino = ++c->highest_ino; | ||
496 | |||
497 | D2(printk(KERN_DEBUG "jffs2_add_ino_cache: Add %p (ino #%u)\n", new, new->ino)); | ||
498 | |||
495 | prev = &c->inocache_list[new->ino % INOCACHE_HASHSIZE]; | 499 | prev = &c->inocache_list[new->ino % INOCACHE_HASHSIZE]; |
496 | 500 | ||
497 | while ((*prev) && (*prev)->ino < new->ino) { | 501 | while ((*prev) && (*prev)->ino < new->ino) { |
@@ -506,7 +510,7 @@ void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new | |||
506 | void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old) | 510 | void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old) |
507 | { | 511 | { |
508 | struct jffs2_inode_cache **prev; | 512 | struct jffs2_inode_cache **prev; |
509 | D2(printk(KERN_DEBUG "jffs2_del_ino_cache: Del %p (ino #%u)\n", old, old->ino)); | 513 | D1(printk(KERN_DEBUG "jffs2_del_ino_cache: Del %p (ino #%u)\n", old, old->ino)); |
510 | spin_lock(&c->inocache_lock); | 514 | spin_lock(&c->inocache_lock); |
511 | 515 | ||
512 | prev = &c->inocache_list[old->ino % INOCACHE_HASHSIZE]; | 516 | prev = &c->inocache_list[old->ino % INOCACHE_HASHSIZE]; |
@@ -518,6 +522,14 @@ void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old) | |||
518 | *prev = old->next; | 522 | *prev = old->next; |
519 | } | 523 | } |
520 | 524 | ||
525 | /* Free it now unless it's in READING or CLEARING state, which | ||
526 | are the transitions upon read_inode() and clear_inode(). The | ||
527 | rest of the time we know nobody else is looking at it, and | ||
528 | if it's held by read_inode() or clear_inode() they'll free it | ||
529 | for themselves. */ | ||
530 | if (old->state != INO_STATE_READING && old->state != INO_STATE_CLEARING) | ||
531 | jffs2_free_inode_cache(old); | ||
532 | |||
521 | spin_unlock(&c->inocache_lock); | 533 | spin_unlock(&c->inocache_lock); |
522 | } | 534 | } |
523 | 535 | ||
@@ -530,7 +542,6 @@ void jffs2_free_ino_caches(struct jffs2_sb_info *c) | |||
530 | this = c->inocache_list[i]; | 542 | this = c->inocache_list[i]; |
531 | while (this) { | 543 | while (this) { |
532 | next = this->next; | 544 | next = this->next; |
533 | D2(printk(KERN_DEBUG "jffs2_free_ino_caches: Freeing ino #%u at %p\n", this->ino, this)); | ||
534 | jffs2_free_inode_cache(this); | 545 | jffs2_free_inode_cache(this); |
535 | this = next; | 546 | this = next; |
536 | } | 547 | } |
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index a4864d05ea92..a65539f28b06 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: nodelist.h,v 1.126 2004/11/19 15:06:29 dedekind Exp $ | 10 | * $Id: nodelist.h,v 1.130 2005/04/09 10:46:59 dedekind Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -135,6 +135,7 @@ struct jffs2_inode_cache { | |||
135 | #define INO_STATE_CHECKEDABSENT 3 /* Checked, cleared again */ | 135 | #define INO_STATE_CHECKEDABSENT 3 /* Checked, cleared again */ |
136 | #define INO_STATE_GC 4 /* GCing a 'pristine' node */ | 136 | #define INO_STATE_GC 4 /* GCing a 'pristine' node */ |
137 | #define INO_STATE_READING 5 /* In read_inode() */ | 137 | #define INO_STATE_READING 5 /* In read_inode() */ |
138 | #define INO_STATE_CLEARING 6 /* In clear_inode() */ | ||
138 | 139 | ||
139 | #define INOCACHE_HASHSIZE 128 | 140 | #define INOCACHE_HASHSIZE 128 |
140 | 141 | ||
@@ -362,6 +363,18 @@ static inline struct jffs2_node_frag *frag_first(struct rb_root *root) | |||
362 | node = node->rb_left; | 363 | node = node->rb_left; |
363 | return rb_entry(node, struct jffs2_node_frag, rb); | 364 | return rb_entry(node, struct jffs2_node_frag, rb); |
364 | } | 365 | } |
366 | |||
367 | static inline struct jffs2_node_frag *frag_last(struct rb_root *root) | ||
368 | { | ||
369 | struct rb_node *node = root->rb_node; | ||
370 | |||
371 | if (!node) | ||
372 | return NULL; | ||
373 | while(node->rb_right) | ||
374 | node = node->rb_right; | ||
375 | return rb_entry(node, struct jffs2_node_frag, rb); | ||
376 | } | ||
377 | |||
365 | #define rb_parent(rb) ((rb)->rb_parent) | 378 | #define rb_parent(rb) ((rb)->rb_parent) |
366 | #define frag_next(frag) rb_entry(rb_next(&(frag)->rb), struct jffs2_node_frag, rb) | 379 | #define frag_next(frag) rb_entry(rb_next(&(frag)->rb), struct jffs2_node_frag, rb) |
367 | #define frag_prev(frag) rb_entry(rb_prev(&(frag)->rb), struct jffs2_node_frag, rb) | 380 | #define frag_prev(frag) rb_entry(rb_prev(&(frag)->rb), struct jffs2_node_frag, rb) |
@@ -462,7 +475,7 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c); | |||
462 | /* erase.c */ | 475 | /* erase.c */ |
463 | void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count); | 476 | void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count); |
464 | 477 | ||
465 | #ifdef CONFIG_JFFS2_FS_NAND | 478 | #ifdef CONFIG_JFFS2_FS_WRITEBUFFER |
466 | /* wbuf.c */ | 479 | /* wbuf.c */ |
467 | int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino); | 480 | int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino); |
468 | int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c); | 481 | int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c); |
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index 2651135bdf42..c1d8b5ed9ab9 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: nodemgmt.c,v 1.115 2004/11/22 11:07:21 dwmw2 Exp $ | 10 | * $Id: nodemgmt.c,v 1.122 2005/05/06 09:30:27 dedekind Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -75,7 +75,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs | |||
75 | dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size + c->unchecked_size; | 75 | dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size + c->unchecked_size; |
76 | if (dirty < c->nospc_dirty_size) { | 76 | if (dirty < c->nospc_dirty_size) { |
77 | if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) { | 77 | if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) { |
78 | printk(KERN_NOTICE "jffs2_reserve_space(): Low on dirty space to GC, but it's a deletion. Allowing...\n"); | 78 | D1(printk(KERN_NOTICE "jffs2_reserve_space(): Low on dirty space to GC, but it's a deletion. Allowing...\n")); |
79 | break; | 79 | break; |
80 | } | 80 | } |
81 | D1(printk(KERN_DEBUG "dirty size 0x%08x + unchecked_size 0x%08x < nospc_dirty_size 0x%08x, returning -ENOSPC\n", | 81 | D1(printk(KERN_DEBUG "dirty size 0x%08x + unchecked_size 0x%08x < nospc_dirty_size 0x%08x, returning -ENOSPC\n", |
@@ -98,7 +98,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs | |||
98 | avail = c->free_size + c->dirty_size + c->erasing_size + c->unchecked_size; | 98 | avail = c->free_size + c->dirty_size + c->erasing_size + c->unchecked_size; |
99 | if ( (avail / c->sector_size) <= blocksneeded) { | 99 | if ( (avail / c->sector_size) <= blocksneeded) { |
100 | if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) { | 100 | if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) { |
101 | printk(KERN_NOTICE "jffs2_reserve_space(): Low on possibly available space, but it's a deletion. Allowing...\n"); | 101 | D1(printk(KERN_NOTICE "jffs2_reserve_space(): Low on possibly available space, but it's a deletion. Allowing...\n")); |
102 | break; | 102 | break; |
103 | } | 103 | } |
104 | 104 | ||
@@ -308,7 +308,10 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r | |||
308 | 308 | ||
309 | D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x(%d), size 0x%x\n", ref_offset(new), ref_flags(new), len)); | 309 | D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x(%d), size 0x%x\n", ref_offset(new), ref_flags(new), len)); |
310 | #if 1 | 310 | #if 1 |
311 | if (jeb != c->nextblock || (ref_offset(new)) != jeb->offset + (c->sector_size - jeb->free_size)) { | 311 | /* we could get some obsolete nodes after nextblock was refiled |
312 | in wbuf.c */ | ||
313 | if ((c->nextblock || !ref_obsolete(new)) | ||
314 | &&(jeb != c->nextblock || ref_offset(new) != jeb->offset + (c->sector_size - jeb->free_size))) { | ||
312 | printk(KERN_WARNING "argh. node added in wrong place\n"); | 315 | printk(KERN_WARNING "argh. node added in wrong place\n"); |
313 | jffs2_free_raw_node_ref(new); | 316 | jffs2_free_raw_node_ref(new); |
314 | return -EINVAL; | 317 | return -EINVAL; |
@@ -332,7 +335,7 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r | |||
332 | c->used_size += len; | 335 | c->used_size += len; |
333 | } | 336 | } |
334 | 337 | ||
335 | if (!jeb->free_size && !jeb->dirty_size) { | 338 | if (!jeb->free_size && !jeb->dirty_size && !ISDIRTY(jeb->wasted_size)) { |
336 | /* If it lives on the dirty_list, jffs2_reserve_space will put it there */ | 339 | /* If it lives on the dirty_list, jffs2_reserve_space will put it there */ |
337 | D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", | 340 | D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", |
338 | jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); | 341 | jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); |
@@ -400,7 +403,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
400 | jeb = &c->blocks[blocknr]; | 403 | jeb = &c->blocks[blocknr]; |
401 | 404 | ||
402 | if (jffs2_can_mark_obsolete(c) && !jffs2_is_readonly(c) && | 405 | if (jffs2_can_mark_obsolete(c) && !jffs2_is_readonly(c) && |
403 | !(c->flags & JFFS2_SB_FLAG_MOUNTING)) { | 406 | !(c->flags & (JFFS2_SB_FLAG_SCANNING | JFFS2_SB_FLAG_BUILDING))) { |
404 | /* Hm. This may confuse static lock analysis. If any of the above | 407 | /* Hm. This may confuse static lock analysis. If any of the above |
405 | three conditions is false, we're going to return from this | 408 | three conditions is false, we're going to return from this |
406 | function without actually obliterating any nodes or freeing | 409 | function without actually obliterating any nodes or freeing |
@@ -434,7 +437,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
434 | 437 | ||
435 | // Take care, that wasted size is taken into concern | 438 | // Take care, that wasted size is taken into concern |
436 | if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + ref_totlen(c, jeb, ref))) && jeb != c->nextblock) { | 439 | if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + ref_totlen(c, jeb, ref))) && jeb != c->nextblock) { |
437 | D1(printk("Dirtying\n")); | 440 | D1(printk(KERN_DEBUG "Dirtying\n")); |
438 | addedsize = ref_totlen(c, jeb, ref); | 441 | addedsize = ref_totlen(c, jeb, ref); |
439 | jeb->dirty_size += ref_totlen(c, jeb, ref); | 442 | jeb->dirty_size += ref_totlen(c, jeb, ref); |
440 | c->dirty_size += ref_totlen(c, jeb, ref); | 443 | c->dirty_size += ref_totlen(c, jeb, ref); |
@@ -456,7 +459,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
456 | } | 459 | } |
457 | } | 460 | } |
458 | } else { | 461 | } else { |
459 | D1(printk("Wasting\n")); | 462 | D1(printk(KERN_DEBUG "Wasting\n")); |
460 | addedsize = 0; | 463 | addedsize = 0; |
461 | jeb->wasted_size += ref_totlen(c, jeb, ref); | 464 | jeb->wasted_size += ref_totlen(c, jeb, ref); |
462 | c->wasted_size += ref_totlen(c, jeb, ref); | 465 | c->wasted_size += ref_totlen(c, jeb, ref); |
@@ -467,8 +470,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
467 | 470 | ||
468 | D1(ACCT_PARANOIA_CHECK(jeb)); | 471 | D1(ACCT_PARANOIA_CHECK(jeb)); |
469 | 472 | ||
470 | if (c->flags & JFFS2_SB_FLAG_MOUNTING) { | 473 | if (c->flags & JFFS2_SB_FLAG_SCANNING) { |
471 | /* Mount in progress. Don't muck about with the block | 474 | /* Flash scanning is in progress. Don't muck about with the block |
472 | lists because they're not ready yet, and don't actually | 475 | lists because they're not ready yet, and don't actually |
473 | obliterate nodes that look obsolete. If they weren't | 476 | obliterate nodes that look obsolete. If they weren't |
474 | marked obsolete on the flash at the time they _became_ | 477 | marked obsolete on the flash at the time they _became_ |
@@ -527,7 +530,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
527 | 530 | ||
528 | spin_unlock(&c->erase_completion_lock); | 531 | spin_unlock(&c->erase_completion_lock); |
529 | 532 | ||
530 | if (!jffs2_can_mark_obsolete(c) || jffs2_is_readonly(c)) { | 533 | if (!jffs2_can_mark_obsolete(c) || jffs2_is_readonly(c) || |
534 | (c->flags & JFFS2_SB_FLAG_BUILDING)) { | ||
531 | /* We didn't lock the erase_free_sem */ | 535 | /* We didn't lock the erase_free_sem */ |
532 | return; | 536 | return; |
533 | } | 537 | } |
@@ -590,11 +594,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
590 | *p = ref->next_in_ino; | 594 | *p = ref->next_in_ino; |
591 | ref->next_in_ino = NULL; | 595 | ref->next_in_ino = NULL; |
592 | 596 | ||
593 | if (ic->nodes == (void *)ic) { | 597 | if (ic->nodes == (void *)ic && ic->nlink == 0) |
594 | D1(printk(KERN_DEBUG "inocache for ino #%u is all gone now. Freeing\n", ic->ino)); | ||
595 | jffs2_del_ino_cache(c, ic); | 598 | jffs2_del_ino_cache(c, ic); |
596 | jffs2_free_inode_cache(ic); | ||
597 | } | ||
598 | 599 | ||
599 | spin_unlock(&c->erase_completion_lock); | 600 | spin_unlock(&c->erase_completion_lock); |
600 | } | 601 | } |
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 03b0acc37b73..5a2d2ee4f641 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: os-linux.h,v 1.51 2004/11/16 20:36:11 dwmw2 Exp $ | 10 | * $Id: os-linux.h,v 1.56 2005/05/03 15:19:00 dedekind Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -97,10 +97,13 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) | |||
97 | #endif | 97 | #endif |
98 | } | 98 | } |
99 | 99 | ||
100 | |||
100 | #define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY) | 101 | #define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY) |
101 | 102 | ||
102 | #if (!defined CONFIG_JFFS2_FS_NAND && !defined CONFIG_JFFS2_FS_NOR_ECC) | 103 | #ifndef CONFIG_JFFS2_FS_WRITEBUFFER |
104 | #define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) ) | ||
103 | #define jffs2_can_mark_obsolete(c) (1) | 105 | #define jffs2_can_mark_obsolete(c) (1) |
106 | #define jffs2_is_writebuffered(c) (0) | ||
104 | #define jffs2_cleanmarker_oob(c) (0) | 107 | #define jffs2_cleanmarker_oob(c) (0) |
105 | #define jffs2_write_nand_cleanmarker(c,jeb) (-EIO) | 108 | #define jffs2_write_nand_cleanmarker(c,jeb) (-EIO) |
106 | 109 | ||
@@ -116,11 +119,14 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) | |||
116 | #define jffs2_wbuf_timeout NULL | 119 | #define jffs2_wbuf_timeout NULL |
117 | #define jffs2_wbuf_process NULL | 120 | #define jffs2_wbuf_process NULL |
118 | #define jffs2_nor_ecc(c) (0) | 121 | #define jffs2_nor_ecc(c) (0) |
122 | #define jffs2_dataflash(c) (0) | ||
119 | #define jffs2_nor_ecc_flash_setup(c) (0) | 123 | #define jffs2_nor_ecc_flash_setup(c) (0) |
120 | #define jffs2_nor_ecc_flash_cleanup(c) do {} while (0) | 124 | #define jffs2_nor_ecc_flash_cleanup(c) do {} while (0) |
121 | 125 | ||
122 | #else /* NAND and/or ECC'd NOR support present */ | 126 | #else /* NAND and/or ECC'd NOR support present */ |
123 | 127 | ||
128 | #define jffs2_is_writebuffered(c) (c->wbuf != NULL) | ||
129 | #define SECTOR_ADDR(x) ( ((unsigned long)(x) / (unsigned long)(c->sector_size)) * c->sector_size ) | ||
124 | #define jffs2_can_mark_obsolete(c) ((c->mtd->type == MTD_NORFLASH && !(c->mtd->flags & MTD_ECC)) || c->mtd->type == MTD_RAM) | 130 | #define jffs2_can_mark_obsolete(c) ((c->mtd->type == MTD_NORFLASH && !(c->mtd->flags & MTD_ECC)) || c->mtd->type == MTD_RAM) |
125 | #define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH) | 131 | #define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH) |
126 | 132 | ||
@@ -142,16 +148,16 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino); | |||
142 | int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c); | 148 | int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c); |
143 | int jffs2_nand_flash_setup(struct jffs2_sb_info *c); | 149 | int jffs2_nand_flash_setup(struct jffs2_sb_info *c); |
144 | void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c); | 150 | void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c); |
145 | #ifdef CONFIG_JFFS2_FS_NOR_ECC | 151 | |
146 | #define jffs2_nor_ecc(c) (c->mtd->type == MTD_NORFLASH && (c->mtd->flags & MTD_ECC)) | 152 | #define jffs2_nor_ecc(c) (c->mtd->type == MTD_NORFLASH && (c->mtd->flags & MTD_ECC)) |
147 | int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c); | 153 | int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c); |
148 | void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c); | 154 | void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c); |
149 | #else | 155 | |
150 | #define jffs2_nor_ecc(c) (0) | 156 | #define jffs2_dataflash(c) (c->mtd->type == MTD_DATAFLASH) |
151 | #define jffs2_nor_ecc_flash_setup(c) (0) | 157 | int jffs2_dataflash_setup(struct jffs2_sb_info *c); |
152 | #define jffs2_nor_ecc_flash_cleanup(c) do {} while (0) | 158 | void jffs2_dataflash_cleanup(struct jffs2_sb_info *c); |
153 | #endif /* NOR ECC */ | 159 | |
154 | #endif /* NAND */ | 160 | #endif /* WRITEBUFFER */ |
155 | 161 | ||
156 | /* erase.c */ | 162 | /* erase.c */ |
157 | static inline void jffs2_erase_pending_trigger(struct jffs2_sb_info *c) | 163 | static inline void jffs2_erase_pending_trigger(struct jffs2_sb_info *c) |
diff --git a/fs/jffs2/read.c b/fs/jffs2/read.c index eb493dc06db7..c7f9068907cf 100644 --- a/fs/jffs2/read.c +++ b/fs/jffs2/read.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: read.c,v 1.38 2004/11/16 20:36:12 dwmw2 Exp $ | 10 | * $Id: read.c,v 1.39 2005/03/01 10:34:03 dedekind Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -214,33 +214,3 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
214 | return 0; | 214 | return 0; |
215 | } | 215 | } |
216 | 216 | ||
217 | /* Core function to read symlink target. */ | ||
218 | char *jffs2_getlink(struct jffs2_sb_info *c, struct jffs2_inode_info *f) | ||
219 | { | ||
220 | char *buf; | ||
221 | int ret; | ||
222 | |||
223 | down(&f->sem); | ||
224 | |||
225 | if (!f->metadata) { | ||
226 | printk(KERN_NOTICE "No metadata for symlink inode #%u\n", f->inocache->ino); | ||
227 | up(&f->sem); | ||
228 | return ERR_PTR(-EINVAL); | ||
229 | } | ||
230 | buf = kmalloc(f->metadata->size+1, GFP_USER); | ||
231 | if (!buf) { | ||
232 | up(&f->sem); | ||
233 | return ERR_PTR(-ENOMEM); | ||
234 | } | ||
235 | buf[f->metadata->size]=0; | ||
236 | |||
237 | ret = jffs2_read_dnode(c, f, f->metadata, buf, 0, f->metadata->size); | ||
238 | |||
239 | up(&f->sem); | ||
240 | |||
241 | if (ret) { | ||
242 | kfree(buf); | ||
243 | return ERR_PTR(ret); | ||
244 | } | ||
245 | return buf; | ||
246 | } | ||
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index aca4a0b17bcd..ef552477c813 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: readinode.c,v 1.117 2004/11/20 18:06:54 dwmw2 Exp $ | 10 | * $Id: readinode.c,v 1.119 2005/03/01 10:34:03 dedekind Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -623,6 +623,40 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
623 | case. */ | 623 | case. */ |
624 | if (!je32_to_cpu(latest_node->isize)) | 624 | if (!je32_to_cpu(latest_node->isize)) |
625 | latest_node->isize = latest_node->dsize; | 625 | latest_node->isize = latest_node->dsize; |
626 | |||
627 | if (f->inocache->state != INO_STATE_CHECKING) { | ||
628 | /* Symlink's inode data is the target path. Read it and | ||
629 | * keep in RAM to facilitate quick follow symlink operation. | ||
630 | * We use f->dents field to store the target path, which | ||
631 | * is somewhat ugly. */ | ||
632 | f->dents = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL); | ||
633 | if (!f->dents) { | ||
634 | printk(KERN_WARNING "Can't allocate %d bytes of memory " | ||
635 | "for the symlink target path cache\n", | ||
636 | je32_to_cpu(latest_node->csize)); | ||
637 | up(&f->sem); | ||
638 | jffs2_do_clear_inode(c, f); | ||
639 | return -ENOMEM; | ||
640 | } | ||
641 | |||
642 | ret = jffs2_flash_read(c, ref_offset(fn->raw) + sizeof(*latest_node), | ||
643 | je32_to_cpu(latest_node->csize), &retlen, (char *)f->dents); | ||
644 | |||
645 | if (ret || retlen != je32_to_cpu(latest_node->csize)) { | ||
646 | if (retlen != je32_to_cpu(latest_node->csize)) | ||
647 | ret = -EIO; | ||
648 | kfree(f->dents); | ||
649 | f->dents = NULL; | ||
650 | up(&f->sem); | ||
651 | jffs2_do_clear_inode(c, f); | ||
652 | return -ret; | ||
653 | } | ||
654 | |||
655 | ((char *)f->dents)[je32_to_cpu(latest_node->csize)] = '\0'; | ||
656 | D1(printk(KERN_DEBUG "jffs2_do_read_inode(): symlink's target '%s' cached\n", | ||
657 | (char *)f->dents)); | ||
658 | } | ||
659 | |||
626 | /* fall through... */ | 660 | /* fall through... */ |
627 | 661 | ||
628 | case S_IFBLK: | 662 | case S_IFBLK: |
@@ -672,6 +706,9 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) | |||
672 | down(&f->sem); | 706 | down(&f->sem); |
673 | deleted = f->inocache && !f->inocache->nlink; | 707 | deleted = f->inocache && !f->inocache->nlink; |
674 | 708 | ||
709 | if (f->inocache && f->inocache->state != INO_STATE_CHECKING) | ||
710 | jffs2_set_inocache_state(c, f->inocache, INO_STATE_CLEARING); | ||
711 | |||
675 | if (f->metadata) { | 712 | if (f->metadata) { |
676 | if (deleted) | 713 | if (deleted) |
677 | jffs2_mark_node_obsolete(c, f->metadata->raw); | 714 | jffs2_mark_node_obsolete(c, f->metadata->raw); |
@@ -680,16 +717,27 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) | |||
680 | 717 | ||
681 | jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL); | 718 | jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL); |
682 | 719 | ||
683 | fds = f->dents; | 720 | /* For symlink inodes we us f->dents to store the target path name */ |
721 | if (S_ISLNK(OFNI_EDONI_2SFFJ(f)->i_mode)) { | ||
722 | if (f->dents) { | ||
723 | kfree(f->dents); | ||
724 | f->dents = NULL; | ||
725 | } | ||
726 | } else { | ||
727 | fds = f->dents; | ||
684 | 728 | ||
685 | while(fds) { | 729 | while(fds) { |
686 | fd = fds; | 730 | fd = fds; |
687 | fds = fd->next; | 731 | fds = fd->next; |
688 | jffs2_free_full_dirent(fd); | 732 | jffs2_free_full_dirent(fd); |
733 | } | ||
689 | } | 734 | } |
690 | 735 | ||
691 | if (f->inocache && f->inocache->state != INO_STATE_CHECKING) | 736 | if (f->inocache && f->inocache->state != INO_STATE_CHECKING) { |
692 | jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); | 737 | jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); |
738 | if (f->inocache->nodes == (void *)f->inocache) | ||
739 | jffs2_del_ino_cache(c, f->inocache); | ||
740 | } | ||
693 | 741 | ||
694 | up(&f->sem); | 742 | up(&f->sem); |
695 | } | 743 | } |
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index ded53584a897..b63160f83bab 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: scan.c,v 1.115 2004/11/17 12:59:08 dedekind Exp $ | 10 | * $Id: scan.c,v 1.119 2005/02/17 17:51:13 dedekind Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
@@ -19,7 +19,7 @@ | |||
19 | #include <linux/compiler.h> | 19 | #include <linux/compiler.h> |
20 | #include "nodelist.h" | 20 | #include "nodelist.h" |
21 | 21 | ||
22 | #define EMPTY_SCAN_SIZE 1024 | 22 | #define DEFAULT_EMPTY_SCAN_SIZE 1024 |
23 | 23 | ||
24 | #define DIRTY_SPACE(x) do { typeof(x) _x = (x); \ | 24 | #define DIRTY_SPACE(x) do { typeof(x) _x = (x); \ |
25 | c->free_size -= _x; c->dirty_size += _x; \ | 25 | c->free_size -= _x; c->dirty_size += _x; \ |
@@ -68,13 +68,21 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo | |||
68 | static inline int min_free(struct jffs2_sb_info *c) | 68 | static inline int min_free(struct jffs2_sb_info *c) |
69 | { | 69 | { |
70 | uint32_t min = 2 * sizeof(struct jffs2_raw_inode); | 70 | uint32_t min = 2 * sizeof(struct jffs2_raw_inode); |
71 | #if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC | 71 | #ifdef CONFIG_JFFS2_FS_WRITEBUFFER |
72 | if (!jffs2_can_mark_obsolete(c) && min < c->wbuf_pagesize) | 72 | if (!jffs2_can_mark_obsolete(c) && min < c->wbuf_pagesize) |
73 | return c->wbuf_pagesize; | 73 | return c->wbuf_pagesize; |
74 | #endif | 74 | #endif |
75 | return min; | 75 | return min; |
76 | 76 | ||
77 | } | 77 | } |
78 | |||
79 | static inline uint32_t EMPTY_SCAN_SIZE(uint32_t sector_size) { | ||
80 | if (sector_size < DEFAULT_EMPTY_SCAN_SIZE) | ||
81 | return sector_size; | ||
82 | else | ||
83 | return DEFAULT_EMPTY_SCAN_SIZE; | ||
84 | } | ||
85 | |||
78 | int jffs2_scan_medium(struct jffs2_sb_info *c) | 86 | int jffs2_scan_medium(struct jffs2_sb_info *c) |
79 | { | 87 | { |
80 | int i, ret; | 88 | int i, ret; |
@@ -220,7 +228,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) | |||
220 | c->dirty_size -= c->nextblock->dirty_size; | 228 | c->dirty_size -= c->nextblock->dirty_size; |
221 | c->nextblock->dirty_size = 0; | 229 | c->nextblock->dirty_size = 0; |
222 | } | 230 | } |
223 | #if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC | 231 | #ifdef CONFIG_JFFS2_FS_WRITEBUFFER |
224 | if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size & (c->wbuf_pagesize-1))) { | 232 | if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size & (c->wbuf_pagesize-1))) { |
225 | /* If we're going to start writing into a block which already | 233 | /* If we're going to start writing into a block which already |
226 | contains data, and the end of the data isn't page-aligned, | 234 | contains data, and the end of the data isn't page-aligned, |
@@ -286,7 +294,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo | |||
286 | uint32_t hdr_crc, buf_ofs, buf_len; | 294 | uint32_t hdr_crc, buf_ofs, buf_len; |
287 | int err; | 295 | int err; |
288 | int noise = 0; | 296 | int noise = 0; |
289 | #ifdef CONFIG_JFFS2_FS_NAND | 297 | #ifdef CONFIG_JFFS2_FS_WRITEBUFFER |
290 | int cleanmarkerfound = 0; | 298 | int cleanmarkerfound = 0; |
291 | #endif | 299 | #endif |
292 | 300 | ||
@@ -295,7 +303,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo | |||
295 | 303 | ||
296 | D1(printk(KERN_DEBUG "jffs2_scan_eraseblock(): Scanning block at 0x%x\n", ofs)); | 304 | D1(printk(KERN_DEBUG "jffs2_scan_eraseblock(): Scanning block at 0x%x\n", ofs)); |
297 | 305 | ||
298 | #ifdef CONFIG_JFFS2_FS_NAND | 306 | #ifdef CONFIG_JFFS2_FS_WRITEBUFFER |
299 | if (jffs2_cleanmarker_oob(c)) { | 307 | if (jffs2_cleanmarker_oob(c)) { |
300 | int ret = jffs2_check_nand_cleanmarker(c, jeb); | 308 | int ret = jffs2_check_nand_cleanmarker(c, jeb); |
301 | D2(printk(KERN_NOTICE "jffs_check_nand_cleanmarker returned %d\n",ret)); | 309 | D2(printk(KERN_NOTICE "jffs_check_nand_cleanmarker returned %d\n",ret)); |
@@ -316,7 +324,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo | |||
316 | if (!buf_size) { | 324 | if (!buf_size) { |
317 | buf_len = c->sector_size; | 325 | buf_len = c->sector_size; |
318 | } else { | 326 | } else { |
319 | buf_len = EMPTY_SCAN_SIZE; | 327 | buf_len = EMPTY_SCAN_SIZE(c->sector_size); |
320 | err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len); | 328 | err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len); |
321 | if (err) | 329 | if (err) |
322 | return err; | 330 | return err; |
@@ -326,11 +334,11 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo | |||
326 | ofs = 0; | 334 | ofs = 0; |
327 | 335 | ||
328 | /* Scan only 4KiB of 0xFF before declaring it's empty */ | 336 | /* Scan only 4KiB of 0xFF before declaring it's empty */ |
329 | while(ofs < EMPTY_SCAN_SIZE && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF) | 337 | while(ofs < EMPTY_SCAN_SIZE(c->sector_size) && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF) |
330 | ofs += 4; | 338 | ofs += 4; |
331 | 339 | ||
332 | if (ofs == EMPTY_SCAN_SIZE) { | 340 | if (ofs == EMPTY_SCAN_SIZE(c->sector_size)) { |
333 | #ifdef CONFIG_JFFS2_FS_NAND | 341 | #ifdef CONFIG_JFFS2_FS_WRITEBUFFER |
334 | if (jffs2_cleanmarker_oob(c)) { | 342 | if (jffs2_cleanmarker_oob(c)) { |
335 | /* scan oob, take care of cleanmarker */ | 343 | /* scan oob, take care of cleanmarker */ |
336 | int ret = jffs2_check_oob_empty(c, jeb, cleanmarkerfound); | 344 | int ret = jffs2_check_oob_empty(c, jeb, cleanmarkerfound); |
@@ -343,7 +351,10 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo | |||
343 | } | 351 | } |
344 | #endif | 352 | #endif |
345 | D1(printk(KERN_DEBUG "Block at 0x%08x is empty (erased)\n", jeb->offset)); | 353 | D1(printk(KERN_DEBUG "Block at 0x%08x is empty (erased)\n", jeb->offset)); |
346 | return BLK_STATE_ALLFF; /* OK to erase if all blocks are like this */ | 354 | if (c->cleanmarker_size == 0) |
355 | return BLK_STATE_CLEANMARKER; /* don't bother with re-erase */ | ||
356 | else | ||
357 | return BLK_STATE_ALLFF; /* OK to erase if all blocks are like this */ | ||
347 | } | 358 | } |
348 | if (ofs) { | 359 | if (ofs) { |
349 | D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset, | 360 | D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset, |
@@ -422,8 +433,8 @@ scan_more: | |||
422 | /* If we're only checking the beginning of a block with a cleanmarker, | 433 | /* If we're only checking the beginning of a block with a cleanmarker, |
423 | bail now */ | 434 | bail now */ |
424 | if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) && | 435 | if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) && |
425 | c->cleanmarker_size && !jeb->dirty_size && !jeb->first_node->next_in_ino) { | 436 | c->cleanmarker_size && !jeb->dirty_size && !jeb->first_node->next_phys) { |
426 | D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE)); | 437 | D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE(c->sector_size))); |
427 | return BLK_STATE_CLEANMARKER; | 438 | return BLK_STATE_CLEANMARKER; |
428 | } | 439 | } |
429 | 440 | ||
@@ -618,7 +629,7 @@ scan_more: | |||
618 | } | 629 | } |
619 | 630 | ||
620 | if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size | 631 | if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size |
621 | && (!jeb->first_node || !jeb->first_node->next_in_ino) ) | 632 | && (!jeb->first_node || !jeb->first_node->next_phys) ) |
622 | return BLK_STATE_CLEANMARKER; | 633 | return BLK_STATE_CLEANMARKER; |
623 | 634 | ||
624 | /* move blocks with max 4 byte dirty space to cleanlist */ | 635 | /* move blocks with max 4 byte dirty space to cleanlist */ |
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 6b2a441d2766..2cf14cf8b35a 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: super.c,v 1.104 2004/11/23 15:37:31 gleixner Exp $ | 10 | * $Id: super.c,v 1.106 2005/05/18 11:37:25 dedekind Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -270,8 +270,6 @@ static void jffs2_put_super (struct super_block *sb) | |||
270 | 270 | ||
271 | D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n")); | 271 | D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n")); |
272 | 272 | ||
273 | if (!(sb->s_flags & MS_RDONLY)) | ||
274 | jffs2_stop_garbage_collect_thread(c); | ||
275 | down(&c->alloc_sem); | 273 | down(&c->alloc_sem); |
276 | jffs2_flush_wbuf_pad(c); | 274 | jffs2_flush_wbuf_pad(c); |
277 | up(&c->alloc_sem); | 275 | up(&c->alloc_sem); |
@@ -292,6 +290,8 @@ static void jffs2_put_super (struct super_block *sb) | |||
292 | static void jffs2_kill_sb(struct super_block *sb) | 290 | static void jffs2_kill_sb(struct super_block *sb) |
293 | { | 291 | { |
294 | struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); | 292 | struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); |
293 | if (!(sb->s_flags & MS_RDONLY)) | ||
294 | jffs2_stop_garbage_collect_thread(c); | ||
295 | generic_shutdown_super(sb); | 295 | generic_shutdown_super(sb); |
296 | put_mtd_device(c->mtd); | 296 | put_mtd_device(c->mtd); |
297 | kfree(c); | 297 | kfree(c); |
@@ -309,7 +309,7 @@ static int __init init_jffs2_fs(void) | |||
309 | int ret; | 309 | int ret; |
310 | 310 | ||
311 | printk(KERN_INFO "JFFS2 version 2.2." | 311 | printk(KERN_INFO "JFFS2 version 2.2." |
312 | #ifdef CONFIG_JFFS2_FS_NAND | 312 | #ifdef CONFIG_JFFS2_FS_WRITEBUFFER |
313 | " (NAND)" | 313 | " (NAND)" |
314 | #endif | 314 | #endif |
315 | " (C) 2001-2003 Red Hat, Inc.\n"); | 315 | " (C) 2001-2003 Red Hat, Inc.\n"); |
diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c index 7b1820d13712..65ab6b001dca 100644 --- a/fs/jffs2/symlink.c +++ b/fs/jffs2/symlink.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: symlink.c,v 1.14 2004/11/16 20:36:12 dwmw2 Exp $ | 10 | * $Id: symlink.c,v 1.16 2005/03/01 10:50:48 dedekind Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -19,27 +19,45 @@ | |||
19 | #include "nodelist.h" | 19 | #include "nodelist.h" |
20 | 20 | ||
21 | static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd); | 21 | static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd); |
22 | static void jffs2_put_link(struct dentry *dentry, struct nameidata *nd); | ||
23 | 22 | ||
24 | struct inode_operations jffs2_symlink_inode_operations = | 23 | struct inode_operations jffs2_symlink_inode_operations = |
25 | { | 24 | { |
26 | .readlink = generic_readlink, | 25 | .readlink = generic_readlink, |
27 | .follow_link = jffs2_follow_link, | 26 | .follow_link = jffs2_follow_link, |
28 | .put_link = jffs2_put_link, | ||
29 | .setattr = jffs2_setattr | 27 | .setattr = jffs2_setattr |
30 | }; | 28 | }; |
31 | 29 | ||
32 | static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd) | 30 | static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd) |
33 | { | 31 | { |
34 | unsigned char *buf; | 32 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode); |
35 | buf = jffs2_getlink(JFFS2_SB_INFO(dentry->d_inode->i_sb), JFFS2_INODE_INFO(dentry->d_inode)); | 33 | |
36 | nd_set_link(nd, buf); | 34 | /* |
35 | * We don't acquire the f->sem mutex here since the only data we | ||
36 | * use is f->dents which in case of the symlink inode points to the | ||
37 | * symlink's target path. | ||
38 | * | ||
39 | * 1. If we are here the inode has already built and f->dents has | ||
40 | * to point to the target path. | ||
41 | * 2. Nobody uses f->dents (if the inode is symlink's inode). The | ||
42 | * exception is inode freeing function which frees f->dents. But | ||
43 | * it can't be called while we are here and before VFS has | ||
44 | * stopped using our f->dents string which we provide by means of | ||
45 | * nd_set_link() call. | ||
46 | */ | ||
47 | |||
48 | if (!f->dents) { | ||
49 | printk(KERN_ERR "jffs2_follow_link(): can't find symlink taerget\n"); | ||
50 | return -EIO; | ||
51 | } | ||
52 | D1(printk(KERN_DEBUG "jffs2_follow_link(): target path is '%s'\n", (char *) f->dents)); | ||
53 | |||
54 | nd_set_link(nd, (char *)f->dents); | ||
55 | |||
56 | /* | ||
57 | * We unlock the f->sem mutex but VFS will use the f->dents string. This is safe | ||
58 | * since the only way that may cause f->dents to be changed is iput() operation. | ||
59 | * But VFS will not use f->dents after iput() has been called. | ||
60 | */ | ||
37 | return 0; | 61 | return 0; |
38 | } | 62 | } |
39 | 63 | ||
40 | static void jffs2_put_link(struct dentry *dentry, struct nameidata *nd) | ||
41 | { | ||
42 | char *s = nd_get_link(nd); | ||
43 | if (!IS_ERR(s)) | ||
44 | kfree(s); | ||
45 | } | ||
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index c8128069ecf0..996d922e503e 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c | |||
@@ -9,7 +9,7 @@ | |||
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 | * |
12 | * $Id: wbuf.c,v 1.82 2004/11/20 22:08:31 dwmw2 Exp $ | 12 | * $Id: wbuf.c,v 1.92 2005/04/05 12:51:54 dedekind Exp $ |
13 | * | 13 | * |
14 | */ | 14 | */ |
15 | 15 | ||
@@ -83,7 +83,7 @@ static void jffs2_wbuf_dirties_inode(struct jffs2_sb_info *c, uint32_t ino) | |||
83 | struct jffs2_inodirty *new; | 83 | struct jffs2_inodirty *new; |
84 | 84 | ||
85 | /* Mark the superblock dirty so that kupdated will flush... */ | 85 | /* Mark the superblock dirty so that kupdated will flush... */ |
86 | OFNI_BS_2SFFJ(c)->s_dirt = 1; | 86 | jffs2_erase_pending_trigger(c); |
87 | 87 | ||
88 | if (jffs2_wbuf_pending_for_ino(c, ino)) | 88 | if (jffs2_wbuf_pending_for_ino(c, ino)) |
89 | return; | 89 | return; |
@@ -130,7 +130,10 @@ static inline void jffs2_refile_wbuf_blocks(struct jffs2_sb_info *c) | |||
130 | } | 130 | } |
131 | } | 131 | } |
132 | 132 | ||
133 | static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) | 133 | #define REFILE_NOTEMPTY 0 |
134 | #define REFILE_ANYWAY 1 | ||
135 | |||
136 | static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, int allow_empty) | ||
134 | { | 137 | { |
135 | D1(printk("About to refile bad block at %08x\n", jeb->offset)); | 138 | D1(printk("About to refile bad block at %08x\n", jeb->offset)); |
136 | 139 | ||
@@ -144,7 +147,7 @@ static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock | |||
144 | D1(printk("Refiling block at %08x to bad_used_list\n", jeb->offset)); | 147 | D1(printk("Refiling block at %08x to bad_used_list\n", jeb->offset)); |
145 | list_add(&jeb->list, &c->bad_used_list); | 148 | list_add(&jeb->list, &c->bad_used_list); |
146 | } else { | 149 | } else { |
147 | BUG(); | 150 | BUG_ON(allow_empty == REFILE_NOTEMPTY); |
148 | /* It has to have had some nodes or we couldn't be here */ | 151 | /* It has to have had some nodes or we couldn't be here */ |
149 | D1(printk("Refiling block at %08x to erase_pending_list\n", jeb->offset)); | 152 | D1(printk("Refiling block at %08x to erase_pending_list\n", jeb->offset)); |
150 | list_add(&jeb->list, &c->erase_pending_list); | 153 | list_add(&jeb->list, &c->erase_pending_list); |
@@ -179,7 +182,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
179 | 182 | ||
180 | jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; | 183 | jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; |
181 | 184 | ||
182 | jffs2_block_refile(c, jeb); | 185 | jffs2_block_refile(c, jeb, REFILE_NOTEMPTY); |
183 | 186 | ||
184 | /* Find the first node to be recovered, by skipping over every | 187 | /* Find the first node to be recovered, by skipping over every |
185 | node which ends before the wbuf starts, or which is obsolete. */ | 188 | node which ends before the wbuf starts, or which is obsolete. */ |
@@ -264,17 +267,16 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
264 | ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len); | 267 | ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len); |
265 | if (ret) { | 268 | if (ret) { |
266 | printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n"); | 269 | printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n"); |
267 | if (buf) | 270 | kfree(buf); |
268 | kfree(buf); | ||
269 | return; | 271 | return; |
270 | } | 272 | } |
271 | if (end-start >= c->wbuf_pagesize) { | 273 | if (end-start >= c->wbuf_pagesize) { |
272 | /* Need to do another write immediately. This, btw, | 274 | /* Need to do another write immediately, but it's possible |
273 | means that we'll be writing from 'buf' and not from | 275 | that this is just because the wbuf itself is completely |
274 | the wbuf. Since if we're writing from the wbuf there | 276 | full, and there's nothing earlier read back from the |
275 | won't be more than a wbuf full of data, now will | 277 | flash. Hence 'buf' isn't necessarily what we're writing |
276 | there? :) */ | 278 | from. */ |
277 | 279 | unsigned char *rewrite_buf = buf?:c->wbuf; | |
278 | uint32_t towrite = (end-start) - ((end-start)%c->wbuf_pagesize); | 280 | uint32_t towrite = (end-start) - ((end-start)%c->wbuf_pagesize); |
279 | 281 | ||
280 | D1(printk(KERN_DEBUG "Write 0x%x bytes at 0x%08x in wbuf recover\n", | 282 | D1(printk(KERN_DEBUG "Write 0x%x bytes at 0x%08x in wbuf recover\n", |
@@ -292,9 +294,9 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
292 | #endif | 294 | #endif |
293 | if (jffs2_cleanmarker_oob(c)) | 295 | if (jffs2_cleanmarker_oob(c)) |
294 | ret = c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen, | 296 | ret = c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen, |
295 | buf, NULL, c->oobinfo); | 297 | rewrite_buf, NULL, c->oobinfo); |
296 | else | 298 | else |
297 | ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, buf); | 299 | ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, rewrite_buf); |
298 | 300 | ||
299 | if (ret || retlen != towrite) { | 301 | if (ret || retlen != towrite) { |
300 | /* Argh. We tried. Really we did. */ | 302 | /* Argh. We tried. Really we did. */ |
@@ -321,10 +323,10 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
321 | 323 | ||
322 | c->wbuf_len = (end - start) - towrite; | 324 | c->wbuf_len = (end - start) - towrite; |
323 | c->wbuf_ofs = ofs + towrite; | 325 | c->wbuf_ofs = ofs + towrite; |
324 | memcpy(c->wbuf, buf + towrite, c->wbuf_len); | 326 | memmove(c->wbuf, rewrite_buf + towrite, c->wbuf_len); |
325 | /* Don't muck about with c->wbuf_inodes. False positives are harmless. */ | 327 | /* Don't muck about with c->wbuf_inodes. False positives are harmless. */ |
326 | 328 | if (buf) | |
327 | kfree(buf); | 329 | kfree(buf); |
328 | } else { | 330 | } else { |
329 | /* OK, now we're left with the dregs in whichever buffer we're using */ | 331 | /* OK, now we're left with the dregs in whichever buffer we're using */ |
330 | if (buf) { | 332 | if (buf) { |
@@ -413,9 +415,9 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) | |||
413 | int ret; | 415 | int ret; |
414 | size_t retlen; | 416 | size_t retlen; |
415 | 417 | ||
416 | /* Nothing to do if not NAND flash. In particular, we shouldn't | 418 | /* Nothing to do if not write-buffering the flash. In particular, we shouldn't |
417 | del_timer() the timer we never initialised. */ | 419 | del_timer() the timer we never initialised. */ |
418 | if (jffs2_can_mark_obsolete(c)) | 420 | if (!jffs2_is_writebuffered(c)) |
419 | return 0; | 421 | return 0; |
420 | 422 | ||
421 | if (!down_trylock(&c->alloc_sem)) { | 423 | if (!down_trylock(&c->alloc_sem)) { |
@@ -424,7 +426,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) | |||
424 | BUG(); | 426 | BUG(); |
425 | } | 427 | } |
426 | 428 | ||
427 | if(!c->wbuf || !c->wbuf_len) | 429 | if (!c->wbuf_len) /* already checked c->wbuf above */ |
428 | return 0; | 430 | return 0; |
429 | 431 | ||
430 | /* claim remaining space on the page | 432 | /* claim remaining space on the page |
@@ -433,7 +435,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) | |||
433 | if we have a switch to next page, we will not have | 435 | if we have a switch to next page, we will not have |
434 | enough remaining space for this. | 436 | enough remaining space for this. |
435 | */ | 437 | */ |
436 | if (pad) { | 438 | if (pad && !jffs2_dataflash(c)) { |
437 | c->wbuf_len = PAD(c->wbuf_len); | 439 | c->wbuf_len = PAD(c->wbuf_len); |
438 | 440 | ||
439 | /* Pad with JFFS2_DIRTY_BITMASK initially. this helps out ECC'd NOR | 441 | /* Pad with JFFS2_DIRTY_BITMASK initially. this helps out ECC'd NOR |
@@ -484,7 +486,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) | |||
484 | spin_lock(&c->erase_completion_lock); | 486 | spin_lock(&c->erase_completion_lock); |
485 | 487 | ||
486 | /* Adjust free size of the block if we padded. */ | 488 | /* Adjust free size of the block if we padded. */ |
487 | if (pad) { | 489 | if (pad && !jffs2_dataflash(c)) { |
488 | struct jffs2_eraseblock *jeb; | 490 | struct jffs2_eraseblock *jeb; |
489 | 491 | ||
490 | jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; | 492 | jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; |
@@ -532,6 +534,9 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino) | |||
532 | 534 | ||
533 | D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() called for ino #%u...\n", ino)); | 535 | D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() called for ino #%u...\n", ino)); |
534 | 536 | ||
537 | if (!c->wbuf) | ||
538 | return 0; | ||
539 | |||
535 | down(&c->alloc_sem); | 540 | down(&c->alloc_sem); |
536 | if (!jffs2_wbuf_pending_for_ino(c, ino)) { | 541 | if (!jffs2_wbuf_pending_for_ino(c, ino)) { |
537 | D1(printk(KERN_DEBUG "Ino #%d not pending in wbuf. Returning\n", ino)); | 542 | D1(printk(KERN_DEBUG "Ino #%d not pending in wbuf. Returning\n", ino)); |
@@ -547,6 +552,10 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino) | |||
547 | D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() padding. Not finished checking\n")); | 552 | D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() padding. Not finished checking\n")); |
548 | down_write(&c->wbuf_sem); | 553 | down_write(&c->wbuf_sem); |
549 | ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); | 554 | ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); |
555 | /* retry flushing wbuf in case jffs2_wbuf_recover | ||
556 | left some data in the wbuf */ | ||
557 | if (ret) | ||
558 | ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); | ||
550 | up_write(&c->wbuf_sem); | 559 | up_write(&c->wbuf_sem); |
551 | } else while (old_wbuf_len && | 560 | } else while (old_wbuf_len && |
552 | old_wbuf_ofs == c->wbuf_ofs) { | 561 | old_wbuf_ofs == c->wbuf_ofs) { |
@@ -561,6 +570,10 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino) | |||
561 | down(&c->alloc_sem); | 570 | down(&c->alloc_sem); |
562 | down_write(&c->wbuf_sem); | 571 | down_write(&c->wbuf_sem); |
563 | ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); | 572 | ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); |
573 | /* retry flushing wbuf in case jffs2_wbuf_recover | ||
574 | left some data in the wbuf */ | ||
575 | if (ret) | ||
576 | ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); | ||
564 | up_write(&c->wbuf_sem); | 577 | up_write(&c->wbuf_sem); |
565 | break; | 578 | break; |
566 | } | 579 | } |
@@ -578,15 +591,27 @@ int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c) | |||
578 | { | 591 | { |
579 | int ret; | 592 | int ret; |
580 | 593 | ||
594 | if (!c->wbuf) | ||
595 | return 0; | ||
596 | |||
581 | down_write(&c->wbuf_sem); | 597 | down_write(&c->wbuf_sem); |
582 | ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT); | 598 | ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT); |
599 | /* retry - maybe wbuf recover left some data in wbuf. */ | ||
600 | if (ret) | ||
601 | ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT); | ||
583 | up_write(&c->wbuf_sem); | 602 | up_write(&c->wbuf_sem); |
584 | 603 | ||
585 | return ret; | 604 | return ret; |
586 | } | 605 | } |
587 | 606 | ||
607 | #ifdef CONFIG_JFFS2_FS_WRITEBUFFER | ||
608 | #define PAGE_DIV(x) ( ((unsigned long)(x) / (unsigned long)(c->wbuf_pagesize)) * (unsigned long)(c->wbuf_pagesize) ) | ||
609 | #define PAGE_MOD(x) ( (unsigned long)(x) % (unsigned long)(c->wbuf_pagesize) ) | ||
610 | #else | ||
588 | #define PAGE_DIV(x) ( (x) & (~(c->wbuf_pagesize - 1)) ) | 611 | #define PAGE_DIV(x) ( (x) & (~(c->wbuf_pagesize - 1)) ) |
589 | #define PAGE_MOD(x) ( (x) & (c->wbuf_pagesize - 1) ) | 612 | #define PAGE_MOD(x) ( (x) & (c->wbuf_pagesize - 1) ) |
613 | #endif | ||
614 | |||
590 | int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino) | 615 | int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino) |
591 | { | 616 | { |
592 | struct kvec outvecs[3]; | 617 | struct kvec outvecs[3]; |
@@ -601,7 +626,7 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig | |||
601 | uint32_t outvec_to = to; | 626 | uint32_t outvec_to = to; |
602 | 627 | ||
603 | /* If not NAND flash, don't bother */ | 628 | /* If not NAND flash, don't bother */ |
604 | if (!c->wbuf) | 629 | if (!jffs2_is_writebuffered(c)) |
605 | return jffs2_flash_direct_writev(c, invecs, count, to, retlen); | 630 | return jffs2_flash_direct_writev(c, invecs, count, to, retlen); |
606 | 631 | ||
607 | down_write(&c->wbuf_sem); | 632 | down_write(&c->wbuf_sem); |
@@ -630,7 +655,7 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig | |||
630 | erase block. Anything else, and you die. | 655 | erase block. Anything else, and you die. |
631 | New block starts at xxx000c (0-b = block header) | 656 | New block starts at xxx000c (0-b = block header) |
632 | */ | 657 | */ |
633 | if ( (to & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) ) { | 658 | if (SECTOR_ADDR(to) != SECTOR_ADDR(c->wbuf_ofs)) { |
634 | /* It's a write to a new block */ | 659 | /* It's a write to a new block */ |
635 | if (c->wbuf_len) { | 660 | if (c->wbuf_len) { |
636 | D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx causes flush of wbuf at 0x%08x\n", (unsigned long)to, c->wbuf_ofs)); | 661 | D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx causes flush of wbuf at 0x%08x\n", (unsigned long)to, c->wbuf_ofs)); |
@@ -762,9 +787,18 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig | |||
762 | 787 | ||
763 | if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) { | 788 | if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) { |
764 | /* At this point we have no problem, | 789 | /* At this point we have no problem, |
765 | c->wbuf is empty. | 790 | c->wbuf is empty. However refile nextblock to avoid |
791 | writing again to same address. | ||
766 | */ | 792 | */ |
767 | *retlen = donelen; | 793 | struct jffs2_eraseblock *jeb; |
794 | |||
795 | spin_lock(&c->erase_completion_lock); | ||
796 | |||
797 | jeb = &c->blocks[outvec_to / c->sector_size]; | ||
798 | jffs2_block_refile(c, jeb, REFILE_ANYWAY); | ||
799 | |||
800 | *retlen = 0; | ||
801 | spin_unlock(&c->erase_completion_lock); | ||
768 | goto exit; | 802 | goto exit; |
769 | } | 803 | } |
770 | 804 | ||
@@ -819,7 +853,7 @@ int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *r | |||
819 | { | 853 | { |
820 | struct kvec vecs[1]; | 854 | struct kvec vecs[1]; |
821 | 855 | ||
822 | if (jffs2_can_mark_obsolete(c)) | 856 | if (!jffs2_is_writebuffered(c)) |
823 | return c->mtd->write(c->mtd, ofs, len, retlen, buf); | 857 | return c->mtd->write(c->mtd, ofs, len, retlen, buf); |
824 | 858 | ||
825 | vecs[0].iov_base = (unsigned char *) buf; | 859 | vecs[0].iov_base = (unsigned char *) buf; |
@@ -835,39 +869,38 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re | |||
835 | loff_t orbf = 0, owbf = 0, lwbf = 0; | 869 | loff_t orbf = 0, owbf = 0, lwbf = 0; |
836 | int ret; | 870 | int ret; |
837 | 871 | ||
838 | /* Read flash */ | 872 | if (!jffs2_is_writebuffered(c)) |
839 | if (!jffs2_can_mark_obsolete(c)) { | ||
840 | down_read(&c->wbuf_sem); | ||
841 | |||
842 | if (jffs2_cleanmarker_oob(c)) | ||
843 | ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo); | ||
844 | else | ||
845 | ret = c->mtd->read(c->mtd, ofs, len, retlen, buf); | ||
846 | |||
847 | if ( (ret == -EBADMSG) && (*retlen == len) ) { | ||
848 | printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n", | ||
849 | len, ofs); | ||
850 | /* | ||
851 | * We have the raw data without ECC correction in the buffer, maybe | ||
852 | * we are lucky and all data or parts are correct. We check the node. | ||
853 | * If data are corrupted node check will sort it out. | ||
854 | * We keep this block, it will fail on write or erase and the we | ||
855 | * mark it bad. Or should we do that now? But we should give him a chance. | ||
856 | * Maybe we had a system crash or power loss before the ecc write or | ||
857 | * a erase was completed. | ||
858 | * So we return success. :) | ||
859 | */ | ||
860 | ret = 0; | ||
861 | } | ||
862 | } else | ||
863 | return c->mtd->read(c->mtd, ofs, len, retlen, buf); | 873 | return c->mtd->read(c->mtd, ofs, len, retlen, buf); |
864 | 874 | ||
875 | /* Read flash */ | ||
876 | down_read(&c->wbuf_sem); | ||
877 | if (jffs2_cleanmarker_oob(c)) | ||
878 | ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo); | ||
879 | else | ||
880 | ret = c->mtd->read(c->mtd, ofs, len, retlen, buf); | ||
881 | |||
882 | if ( (ret == -EBADMSG) && (*retlen == len) ) { | ||
883 | printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n", | ||
884 | len, ofs); | ||
885 | /* | ||
886 | * We have the raw data without ECC correction in the buffer, maybe | ||
887 | * we are lucky and all data or parts are correct. We check the node. | ||
888 | * If data are corrupted node check will sort it out. | ||
889 | * We keep this block, it will fail on write or erase and the we | ||
890 | * mark it bad. Or should we do that now? But we should give him a chance. | ||
891 | * Maybe we had a system crash or power loss before the ecc write or | ||
892 | * a erase was completed. | ||
893 | * So we return success. :) | ||
894 | */ | ||
895 | ret = 0; | ||
896 | } | ||
897 | |||
865 | /* if no writebuffer available or write buffer empty, return */ | 898 | /* if no writebuffer available or write buffer empty, return */ |
866 | if (!c->wbuf_pagesize || !c->wbuf_len) | 899 | if (!c->wbuf_pagesize || !c->wbuf_len) |
867 | goto exit; | 900 | goto exit; |
868 | 901 | ||
869 | /* if we read in a different block, return */ | 902 | /* if we read in a different block, return */ |
870 | if ( (ofs & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) ) | 903 | if (SECTOR_ADDR(ofs) != SECTOR_ADDR(c->wbuf_ofs)) |
871 | goto exit; | 904 | goto exit; |
872 | 905 | ||
873 | if (ofs >= c->wbuf_ofs) { | 906 | if (ofs >= c->wbuf_ofs) { |
@@ -1161,7 +1194,27 @@ void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c) | |||
1161 | kfree(c->wbuf); | 1194 | kfree(c->wbuf); |
1162 | } | 1195 | } |
1163 | 1196 | ||
1164 | #ifdef CONFIG_JFFS2_FS_NOR_ECC | 1197 | int jffs2_dataflash_setup(struct jffs2_sb_info *c) { |
1198 | c->cleanmarker_size = 0; /* No cleanmarkers needed */ | ||
1199 | |||
1200 | /* Initialize write buffer */ | ||
1201 | init_rwsem(&c->wbuf_sem); | ||
1202 | c->wbuf_pagesize = c->sector_size; | ||
1203 | c->wbuf_ofs = 0xFFFFFFFF; | ||
1204 | |||
1205 | c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); | ||
1206 | if (!c->wbuf) | ||
1207 | return -ENOMEM; | ||
1208 | |||
1209 | printk(KERN_INFO "JFFS2 write-buffering enabled (%i)\n", c->wbuf_pagesize); | ||
1210 | |||
1211 | return 0; | ||
1212 | } | ||
1213 | |||
1214 | void jffs2_dataflash_cleanup(struct jffs2_sb_info *c) { | ||
1215 | kfree(c->wbuf); | ||
1216 | } | ||
1217 | |||
1165 | int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) { | 1218 | int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) { |
1166 | /* Cleanmarker is actually larger on the flashes */ | 1219 | /* Cleanmarker is actually larger on the flashes */ |
1167 | c->cleanmarker_size = 16; | 1220 | c->cleanmarker_size = 16; |
@@ -1181,4 +1234,3 @@ int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) { | |||
1181 | void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c) { | 1234 | void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c) { |
1182 | kfree(c->wbuf); | 1235 | kfree(c->wbuf); |
1183 | } | 1236 | } |
1184 | #endif | ||
diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c index 80a5db542629..69100615d9ae 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: write.c,v 1.87 2004/11/16 20:36:12 dwmw2 Exp $ | 10 | * $Id: write.c,v 1.92 2005/04/13 13:22:35 dwmw2 Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -35,13 +35,12 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint | |||
35 | f->inocache = ic; | 35 | f->inocache = ic; |
36 | f->inocache->nlink = 1; | 36 | f->inocache->nlink = 1; |
37 | f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; | 37 | f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; |
38 | f->inocache->ino = ++c->highest_ino; | ||
39 | f->inocache->state = INO_STATE_PRESENT; | 38 | f->inocache->state = INO_STATE_PRESENT; |
40 | 39 | ||
41 | ri->ino = cpu_to_je32(f->inocache->ino); | ||
42 | 40 | ||
43 | D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino)); | ||
44 | jffs2_add_ino_cache(c, f->inocache); | 41 | jffs2_add_ino_cache(c, f->inocache); |
42 | D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino)); | ||
43 | ri->ino = cpu_to_je32(f->inocache->ino); | ||
45 | 44 | ||
46 | ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | 45 | ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
47 | ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); | 46 | ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); |
@@ -136,6 +135,15 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 | |||
136 | raw->__totlen = PAD(sizeof(*ri)+datalen); | 135 | raw->__totlen = PAD(sizeof(*ri)+datalen); |
137 | raw->next_phys = NULL; | 136 | raw->next_phys = NULL; |
138 | 137 | ||
138 | if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(ri->version) < f->highest_version)) { | ||
139 | BUG_ON(!retried); | ||
140 | D1(printk(KERN_DEBUG "jffs2_write_dnode : dnode_version %d, " | ||
141 | "highest version %d -> updating dnode\n", | ||
142 | je32_to_cpu(ri->version), f->highest_version)); | ||
143 | ri->version = cpu_to_je32(++f->highest_version); | ||
144 | ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); | ||
145 | } | ||
146 | |||
139 | ret = jffs2_flash_writev(c, vecs, cnt, flash_ofs, &retlen, | 147 | ret = jffs2_flash_writev(c, vecs, cnt, flash_ofs, &retlen, |
140 | (alloc_mode==ALLOC_GC)?0:f->inocache->ino); | 148 | (alloc_mode==ALLOC_GC)?0:f->inocache->ino); |
141 | 149 | ||
@@ -280,6 +288,16 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff | |||
280 | raw->__totlen = PAD(sizeof(*rd)+namelen); | 288 | raw->__totlen = PAD(sizeof(*rd)+namelen); |
281 | raw->next_phys = NULL; | 289 | raw->next_phys = NULL; |
282 | 290 | ||
291 | if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(rd->version) < f->highest_version)) { | ||
292 | BUG_ON(!retried); | ||
293 | D1(printk(KERN_DEBUG "jffs2_write_dirent : dirent_version %d, " | ||
294 | "highest version %d -> updating dirent\n", | ||
295 | je32_to_cpu(rd->version), f->highest_version)); | ||
296 | rd->version = cpu_to_je32(++f->highest_version); | ||
297 | fd->version = je32_to_cpu(rd->version); | ||
298 | rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); | ||
299 | } | ||
300 | |||
283 | ret = jffs2_flash_writev(c, vecs, 2, flash_ofs, &retlen, | 301 | ret = jffs2_flash_writev(c, vecs, 2, flash_ofs, &retlen, |
284 | (alloc_mode==ALLOC_GC)?0:je32_to_cpu(rd->pino)); | 302 | (alloc_mode==ALLOC_GC)?0:je32_to_cpu(rd->pino)); |
285 | if (ret || (retlen != sizeof(*rd) + namelen)) { | 303 | if (ret || (retlen != sizeof(*rd) + namelen)) { |
@@ -625,20 +643,23 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, | |||
625 | 643 | ||
626 | down(&dead_f->sem); | 644 | down(&dead_f->sem); |
627 | 645 | ||
628 | while (dead_f->dents) { | 646 | if (S_ISDIR(OFNI_EDONI_2SFFJ(dead_f)->i_mode)) { |
629 | /* There can be only deleted ones */ | 647 | while (dead_f->dents) { |
630 | fd = dead_f->dents; | 648 | /* There can be only deleted ones */ |
631 | 649 | fd = dead_f->dents; | |
632 | dead_f->dents = fd->next; | 650 | |
633 | 651 | dead_f->dents = fd->next; | |
634 | if (fd->ino) { | 652 | |
635 | printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n", | 653 | if (fd->ino) { |
636 | dead_f->inocache->ino, fd->name, fd->ino); | 654 | printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n", |
637 | } else { | 655 | dead_f->inocache->ino, fd->name, fd->ino); |
638 | D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n", fd->name, dead_f->inocache->ino)); | 656 | } else { |
657 | D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n", | ||
658 | fd->name, dead_f->inocache->ino)); | ||
659 | } | ||
660 | jffs2_mark_node_obsolete(c, fd->raw); | ||
661 | jffs2_free_full_dirent(fd); | ||
639 | } | 662 | } |
640 | jffs2_mark_node_obsolete(c, fd->raw); | ||
641 | jffs2_free_full_dirent(fd); | ||
642 | } | 663 | } |
643 | 664 | ||
644 | dead_f->inocache->nlink--; | 665 | dead_f->inocache->nlink--; |