diff options
Diffstat (limited to 'fs/jffs2')
-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 | 46 | ||||
-rw-r--r-- | fs/jffs2/erase.c | 24 | ||||
-rw-r--r-- | fs/jffs2/file.c | 5 | ||||
-rw-r--r-- | fs/jffs2/fs.c | 24 | ||||
-rw-r--r-- | fs/jffs2/gc.c | 41 | ||||
-rw-r--r-- | fs/jffs2/nodelist.c | 93 | ||||
-rw-r--r-- | fs/jffs2/nodelist.h | 21 | ||||
-rw-r--r-- | fs/jffs2/nodemgmt.c | 31 | ||||
-rw-r--r-- | fs/jffs2/os-linux.h | 60 | ||||
-rw-r--r-- | fs/jffs2/read.c | 32 | ||||
-rw-r--r-- | fs/jffs2/readinode.c | 96 | ||||
-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, 524 insertions, 294 deletions
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..3ca0d25eef1d 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.86 2005/07/06 12:13:09 dwmw2 Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -22,16 +22,6 @@ | |||
22 | #include <linux/time.h> | 22 | #include <linux/time.h> |
23 | #include "nodelist.h" | 23 | #include "nodelist.h" |
24 | 24 | ||
25 | /* Urgh. Please tell me there's a nicer way of doing these. */ | ||
26 | #include <linux/version.h> | ||
27 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,48) | ||
28 | typedef int mknod_arg_t; | ||
29 | #define NAMEI_COMPAT(x) ((void *)x) | ||
30 | #else | ||
31 | typedef dev_t mknod_arg_t; | ||
32 | #define NAMEI_COMPAT(x) (x) | ||
33 | #endif | ||
34 | |||
35 | static int jffs2_readdir (struct file *, void *, filldir_t); | 25 | static int jffs2_readdir (struct file *, void *, filldir_t); |
36 | 26 | ||
37 | static int jffs2_create (struct inode *,struct dentry *,int, | 27 | static int jffs2_create (struct inode *,struct dentry *,int, |
@@ -43,7 +33,7 @@ static int jffs2_unlink (struct inode *,struct dentry *); | |||
43 | static int jffs2_symlink (struct inode *,struct dentry *,const char *); | 33 | static int jffs2_symlink (struct inode *,struct dentry *,const char *); |
44 | static int jffs2_mkdir (struct inode *,struct dentry *,int); | 34 | static int jffs2_mkdir (struct inode *,struct dentry *,int); |
45 | static int jffs2_rmdir (struct inode *,struct dentry *); | 35 | static int jffs2_rmdir (struct inode *,struct dentry *); |
46 | static int jffs2_mknod (struct inode *,struct dentry *,int,mknod_arg_t); | 36 | static int jffs2_mknod (struct inode *,struct dentry *,int,dev_t); |
47 | static int jffs2_rename (struct inode *, struct dentry *, | 37 | static int jffs2_rename (struct inode *, struct dentry *, |
48 | struct inode *, struct dentry *); | 38 | struct inode *, struct dentry *); |
49 | 39 | ||
@@ -58,8 +48,8 @@ struct file_operations jffs2_dir_operations = | |||
58 | 48 | ||
59 | struct inode_operations jffs2_dir_inode_operations = | 49 | struct inode_operations jffs2_dir_inode_operations = |
60 | { | 50 | { |
61 | .create = NAMEI_COMPAT(jffs2_create), | 51 | .create = jffs2_create, |
62 | .lookup = NAMEI_COMPAT(jffs2_lookup), | 52 | .lookup = jffs2_lookup, |
63 | .link = jffs2_link, | 53 | .link = jffs2_link, |
64 | .unlink = jffs2_unlink, | 54 | .unlink = jffs2_unlink, |
65 | .symlink = jffs2_symlink, | 55 | .symlink = jffs2_symlink, |
@@ -296,11 +286,11 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
296 | struct jffs2_full_dirent *fd; | 286 | struct jffs2_full_dirent *fd; |
297 | int namelen; | 287 | int namelen; |
298 | uint32_t alloclen, phys_ofs; | 288 | uint32_t alloclen, phys_ofs; |
299 | int ret; | 289 | int ret, targetlen = strlen(target); |
300 | 290 | ||
301 | /* FIXME: If you care. We'd need to use frags for the target | 291 | /* FIXME: If you care. We'd need to use frags for the target |
302 | if it grows much more than this */ | 292 | if it grows much more than this */ |
303 | if (strlen(target) > 254) | 293 | if (targetlen > 254) |
304 | return -EINVAL; | 294 | return -EINVAL; |
305 | 295 | ||
306 | ri = jffs2_alloc_raw_inode(); | 296 | ri = jffs2_alloc_raw_inode(); |
@@ -314,7 +304,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
314 | * Just the node will do for now, though | 304 | * Just the node will do for now, though |
315 | */ | 305 | */ |
316 | namelen = dentry->d_name.len; | 306 | namelen = dentry->d_name.len; |
317 | ret = jffs2_reserve_space(c, sizeof(*ri) + strlen(target), &phys_ofs, &alloclen, ALLOC_NORMAL); | 307 | ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &phys_ofs, &alloclen, ALLOC_NORMAL); |
318 | 308 | ||
319 | if (ret) { | 309 | if (ret) { |
320 | jffs2_free_raw_inode(ri); | 310 | jffs2_free_raw_inode(ri); |
@@ -333,16 +323,16 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
333 | 323 | ||
334 | f = JFFS2_INODE_INFO(inode); | 324 | f = JFFS2_INODE_INFO(inode); |
335 | 325 | ||
336 | inode->i_size = strlen(target); | 326 | inode->i_size = targetlen; |
337 | ri->isize = ri->dsize = ri->csize = cpu_to_je32(inode->i_size); | 327 | ri->isize = ri->dsize = ri->csize = cpu_to_je32(inode->i_size); |
338 | ri->totlen = cpu_to_je32(sizeof(*ri) + inode->i_size); | 328 | 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)); | 329 | ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); |
340 | 330 | ||
341 | ri->compr = JFFS2_COMPR_NONE; | 331 | ri->compr = JFFS2_COMPR_NONE; |
342 | ri->data_crc = cpu_to_je32(crc32(0, target, strlen(target))); | 332 | ri->data_crc = cpu_to_je32(crc32(0, target, targetlen)); |
343 | ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); | 333 | ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); |
344 | 334 | ||
345 | fn = jffs2_write_dnode(c, f, ri, target, strlen(target), phys_ofs, ALLOC_NORMAL); | 335 | fn = jffs2_write_dnode(c, f, ri, target, targetlen, phys_ofs, ALLOC_NORMAL); |
346 | 336 | ||
347 | jffs2_free_raw_inode(ri); | 337 | jffs2_free_raw_inode(ri); |
348 | 338 | ||
@@ -353,6 +343,20 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
353 | jffs2_clear_inode(inode); | 343 | jffs2_clear_inode(inode); |
354 | return PTR_ERR(fn); | 344 | return PTR_ERR(fn); |
355 | } | 345 | } |
346 | |||
347 | /* We use f->dents field to store the target path. */ | ||
348 | f->dents = kmalloc(targetlen + 1, GFP_KERNEL); | ||
349 | if (!f->dents) { | ||
350 | printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1); | ||
351 | up(&f->sem); | ||
352 | jffs2_complete_reservation(c); | ||
353 | jffs2_clear_inode(inode); | ||
354 | return -ENOMEM; | ||
355 | } | ||
356 | |||
357 | memcpy(f->dents, target, targetlen + 1); | ||
358 | D1(printk(KERN_DEBUG "jffs2_symlink: symlink's target '%s' cached\n", (char *)f->dents)); | ||
359 | |||
356 | /* No data here. Only a metadata node, which will be | 360 | /* No data here. Only a metadata node, which will be |
357 | obsoleted by the first data write | 361 | obsoleted by the first data write |
358 | */ | 362 | */ |
@@ -564,7 +568,7 @@ static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry) | |||
564 | return ret; | 568 | return ret; |
565 | } | 569 | } |
566 | 570 | ||
567 | static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, mknod_arg_t rdev) | 571 | static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, dev_t rdev) |
568 | { | 572 | { |
569 | struct jffs2_inode_info *f, *dir_f; | 573 | struct jffs2_inode_info *f, *dir_f; |
570 | struct jffs2_sb_info *c; | 574 | struct jffs2_sb_info *c; |
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/file.c b/fs/jffs2/file.c index 771a554701d6..bd9ed9b0247b 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c | |||
@@ -7,11 +7,10 @@ | |||
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: file.c,v 1.99 2004/11/16 20:36:11 dwmw2 Exp $ | 10 | * $Id: file.c,v 1.102 2005/07/06 12:13:09 dwmw2 Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/version.h> | ||
15 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
16 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
17 | #include <linux/fs.h> | 16 | #include <linux/fs.h> |
@@ -51,9 +50,7 @@ struct file_operations jffs2_file_operations = | |||
51 | .ioctl = jffs2_ioctl, | 50 | .ioctl = jffs2_ioctl, |
52 | .mmap = generic_file_readonly_mmap, | 51 | .mmap = generic_file_readonly_mmap, |
53 | .fsync = jffs2_fsync, | 52 | .fsync = jffs2_fsync, |
54 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,29) | ||
55 | .sendfile = generic_file_sendfile | 53 | .sendfile = generic_file_sendfile |
56 | #endif | ||
57 | }; | 54 | }; |
58 | 55 | ||
59 | /* jffs2_file_inode_operations */ | 56 | /* jffs2_file_inode_operations */ |
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 30ab233fe423..5687c3f42002 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c | |||
@@ -7,11 +7,10 @@ | |||
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.56 2005/07/06 12:13:09 dwmw2 Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/version.h> | ||
15 | #include <linux/config.h> | 14 | #include <linux/config.h> |
16 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
17 | #include <linux/sched.h> | 16 | #include <linux/sched.h> |
@@ -450,11 +449,15 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) | |||
450 | 449 | ||
451 | c = JFFS2_SB_INFO(sb); | 450 | c = JFFS2_SB_INFO(sb); |
452 | 451 | ||
453 | #ifndef CONFIG_JFFS2_FS_NAND | 452 | #ifndef CONFIG_JFFS2_FS_WRITEBUFFER |
454 | if (c->mtd->type == MTD_NANDFLASH) { | 453 | if (c->mtd->type == MTD_NANDFLASH) { |
455 | printk(KERN_ERR "jffs2: Cannot operate on NAND flash unless jffs2 NAND support is compiled in.\n"); | 454 | printk(KERN_ERR "jffs2: Cannot operate on NAND flash unless jffs2 NAND support is compiled in.\n"); |
456 | return -EINVAL; | 455 | return -EINVAL; |
457 | } | 456 | } |
457 | if (c->mtd->type == MTD_DATAFLASH) { | ||
458 | printk(KERN_ERR "jffs2: Cannot operate on DataFlash unless jffs2 DataFlash support is compiled in.\n"); | ||
459 | return -EINVAL; | ||
460 | } | ||
458 | #endif | 461 | #endif |
459 | 462 | ||
460 | c->flash_size = c->mtd->size; | 463 | c->flash_size = c->mtd->size; |
@@ -522,9 +525,7 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) | |||
522 | if (!sb->s_root) | 525 | if (!sb->s_root) |
523 | goto out_root_i; | 526 | goto out_root_i; |
524 | 527 | ||
525 | #if LINUX_VERSION_CODE >= 0x20403 | ||
526 | sb->s_maxbytes = 0xFFFFFFFF; | 528 | sb->s_maxbytes = 0xFFFFFFFF; |
527 | #endif | ||
528 | sb->s_blocksize = PAGE_CACHE_SIZE; | 529 | sb->s_blocksize = PAGE_CACHE_SIZE; |
529 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; | 530 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; |
530 | sb->s_magic = JFFS2_SUPER_MAGIC; | 531 | sb->s_magic = JFFS2_SUPER_MAGIC; |
@@ -661,6 +662,14 @@ static int jffs2_flash_setup(struct jffs2_sb_info *c) { | |||
661 | if (ret) | 662 | if (ret) |
662 | return ret; | 663 | return ret; |
663 | } | 664 | } |
665 | |||
666 | /* and Dataflash */ | ||
667 | if (jffs2_dataflash(c)) { | ||
668 | ret = jffs2_dataflash_setup(c); | ||
669 | if (ret) | ||
670 | return ret; | ||
671 | } | ||
672 | |||
664 | return ret; | 673 | return ret; |
665 | } | 674 | } |
666 | 675 | ||
@@ -674,4 +683,9 @@ void jffs2_flash_cleanup(struct jffs2_sb_info *c) { | |||
674 | if (jffs2_nor_ecc(c)) { | 683 | if (jffs2_nor_ecc(c)) { |
675 | jffs2_nor_ecc_flash_cleanup(c); | 684 | jffs2_nor_ecc_flash_cleanup(c); |
676 | } | 685 | } |
686 | |||
687 | /* and DataFlash */ | ||
688 | if (jffs2_dataflash(c)) { | ||
689 | jffs2_dataflash_cleanup(c); | ||
690 | } | ||
677 | } | 691 | } |
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..c7bbdeec93a6 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.97 2005/07/06 15:18:41 dwmw2 Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -58,27 +58,60 @@ void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new | |||
58 | /* Put a new tmp_dnode_info into the list, keeping the list in | 58 | /* Put a new tmp_dnode_info into the list, keeping the list in |
59 | order of increasing version | 59 | order of increasing version |
60 | */ | 60 | */ |
61 | static void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct jffs2_tmp_dnode_info **list) | 61 | |
62 | static void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct rb_root *list) | ||
62 | { | 63 | { |
63 | struct jffs2_tmp_dnode_info **prev = list; | 64 | struct rb_node **p = &list->rb_node; |
64 | 65 | struct rb_node * parent = NULL; | |
65 | while ((*prev) && (*prev)->version < tn->version) { | 66 | struct jffs2_tmp_dnode_info *this; |
66 | prev = &((*prev)->next); | 67 | |
67 | } | 68 | while (*p) { |
68 | tn->next = (*prev); | 69 | parent = *p; |
69 | *prev = tn; | 70 | this = rb_entry(parent, struct jffs2_tmp_dnode_info, rb); |
71 | |||
72 | /* There may actually be a collision here, but it doesn't | ||
73 | actually matter. As long as the two nodes with the same | ||
74 | version are together, it's all fine. */ | ||
75 | if (tn->version < this->version) | ||
76 | p = &(*p)->rb_left; | ||
77 | else | ||
78 | p = &(*p)->rb_right; | ||
79 | } | ||
80 | |||
81 | rb_link_node(&tn->rb, parent, p); | ||
82 | rb_insert_color(&tn->rb, list); | ||
70 | } | 83 | } |
71 | 84 | ||
72 | static void jffs2_free_tmp_dnode_info_list(struct jffs2_tmp_dnode_info *tn) | 85 | static void jffs2_free_tmp_dnode_info_list(struct rb_root *list) |
73 | { | 86 | { |
74 | struct jffs2_tmp_dnode_info *next; | 87 | struct rb_node *this; |
88 | struct jffs2_tmp_dnode_info *tn; | ||
89 | |||
90 | this = list->rb_node; | ||
91 | |||
92 | /* Now at bottom of tree */ | ||
93 | while (this) { | ||
94 | if (this->rb_left) | ||
95 | this = this->rb_left; | ||
96 | else if (this->rb_right) | ||
97 | this = this->rb_right; | ||
98 | else { | ||
99 | tn = rb_entry(this, struct jffs2_tmp_dnode_info, rb); | ||
100 | jffs2_free_full_dnode(tn->fn); | ||
101 | jffs2_free_tmp_dnode_info(tn); | ||
102 | |||
103 | this = this->rb_parent; | ||
104 | if (!this) | ||
105 | break; | ||
75 | 106 | ||
76 | while (tn) { | 107 | if (this->rb_left == &tn->rb) |
77 | next = tn; | 108 | this->rb_left = NULL; |
78 | tn = tn->next; | 109 | else if (this->rb_right == &tn->rb) |
79 | jffs2_free_full_dnode(next->fn); | 110 | this->rb_right = NULL; |
80 | jffs2_free_tmp_dnode_info(next); | 111 | else BUG(); |
112 | } | ||
81 | } | 113 | } |
114 | list->rb_node = NULL; | ||
82 | } | 115 | } |
83 | 116 | ||
84 | static void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd) | 117 | static void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd) |
@@ -108,12 +141,13 @@ static struct jffs2_raw_node_ref *jffs2_first_valid_node(struct jffs2_raw_node_r | |||
108 | with this ino, returning the former in order of version */ | 141 | with this ino, returning the former in order of version */ |
109 | 142 | ||
110 | int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | 143 | int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f, |
111 | struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp, | 144 | struct rb_root *tnp, struct jffs2_full_dirent **fdp, |
112 | uint32_t *highest_version, uint32_t *latest_mctime, | 145 | uint32_t *highest_version, uint32_t *latest_mctime, |
113 | uint32_t *mctime_ver) | 146 | uint32_t *mctime_ver) |
114 | { | 147 | { |
115 | struct jffs2_raw_node_ref *ref, *valid_ref; | 148 | struct jffs2_raw_node_ref *ref, *valid_ref; |
116 | struct jffs2_tmp_dnode_info *tn, *ret_tn = NULL; | 149 | struct jffs2_tmp_dnode_info *tn; |
150 | struct rb_root ret_tn = RB_ROOT; | ||
117 | struct jffs2_full_dirent *fd, *ret_fd = NULL; | 151 | struct jffs2_full_dirent *fd, *ret_fd = NULL; |
118 | union jffs2_node_union node; | 152 | union jffs2_node_union node; |
119 | size_t retlen; | 153 | size_t retlen; |
@@ -127,7 +161,7 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
127 | 161 | ||
128 | valid_ref = jffs2_first_valid_node(f->inocache->nodes); | 162 | valid_ref = jffs2_first_valid_node(f->inocache->nodes); |
129 | 163 | ||
130 | if (!valid_ref) | 164 | if (!valid_ref && (f->inocache->ino != 1)) |
131 | printk(KERN_WARNING "Eep. No valid nodes for ino #%u\n", f->inocache->ino); | 165 | printk(KERN_WARNING "Eep. No valid nodes for ino #%u\n", f->inocache->ino); |
132 | 166 | ||
133 | while (valid_ref) { | 167 | while (valid_ref) { |
@@ -450,7 +484,7 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
450 | return 0; | 484 | return 0; |
451 | 485 | ||
452 | free_out: | 486 | free_out: |
453 | jffs2_free_tmp_dnode_info_list(ret_tn); | 487 | jffs2_free_tmp_dnode_info_list(&ret_tn); |
454 | jffs2_free_full_dirent_list(ret_fd); | 488 | jffs2_free_full_dirent_list(ret_fd); |
455 | return err; | 489 | return err; |
456 | } | 490 | } |
@@ -489,9 +523,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) | 523 | void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new) |
490 | { | 524 | { |
491 | struct jffs2_inode_cache **prev; | 525 | struct jffs2_inode_cache **prev; |
492 | D2(printk(KERN_DEBUG "jffs2_add_ino_cache: Add %p (ino #%u)\n", new, new->ino)); | 526 | |
493 | spin_lock(&c->inocache_lock); | 527 | spin_lock(&c->inocache_lock); |
494 | 528 | if (!new->ino) | |
529 | new->ino = ++c->highest_ino; | ||
530 | |||
531 | D2(printk(KERN_DEBUG "jffs2_add_ino_cache: Add %p (ino #%u)\n", new, new->ino)); | ||
532 | |||
495 | prev = &c->inocache_list[new->ino % INOCACHE_HASHSIZE]; | 533 | prev = &c->inocache_list[new->ino % INOCACHE_HASHSIZE]; |
496 | 534 | ||
497 | while ((*prev) && (*prev)->ino < new->ino) { | 535 | while ((*prev) && (*prev)->ino < new->ino) { |
@@ -506,7 +544,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) | 544 | void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old) |
507 | { | 545 | { |
508 | struct jffs2_inode_cache **prev; | 546 | struct jffs2_inode_cache **prev; |
509 | D2(printk(KERN_DEBUG "jffs2_del_ino_cache: Del %p (ino #%u)\n", old, old->ino)); | 547 | D1(printk(KERN_DEBUG "jffs2_del_ino_cache: Del %p (ino #%u)\n", old, old->ino)); |
510 | spin_lock(&c->inocache_lock); | 548 | spin_lock(&c->inocache_lock); |
511 | 549 | ||
512 | prev = &c->inocache_list[old->ino % INOCACHE_HASHSIZE]; | 550 | prev = &c->inocache_list[old->ino % INOCACHE_HASHSIZE]; |
@@ -518,6 +556,14 @@ void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old) | |||
518 | *prev = old->next; | 556 | *prev = old->next; |
519 | } | 557 | } |
520 | 558 | ||
559 | /* Free it now unless it's in READING or CLEARING state, which | ||
560 | are the transitions upon read_inode() and clear_inode(). The | ||
561 | rest of the time we know nobody else is looking at it, and | ||
562 | if it's held by read_inode() or clear_inode() they'll free it | ||
563 | for themselves. */ | ||
564 | if (old->state != INO_STATE_READING && old->state != INO_STATE_CLEARING) | ||
565 | jffs2_free_inode_cache(old); | ||
566 | |||
521 | spin_unlock(&c->inocache_lock); | 567 | spin_unlock(&c->inocache_lock); |
522 | } | 568 | } |
523 | 569 | ||
@@ -530,7 +576,6 @@ void jffs2_free_ino_caches(struct jffs2_sb_info *c) | |||
530 | this = c->inocache_list[i]; | 576 | this = c->inocache_list[i]; |
531 | while (this) { | 577 | while (this) { |
532 | next = this->next; | 578 | 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); | 579 | jffs2_free_inode_cache(this); |
535 | this = next; | 580 | this = next; |
536 | } | 581 | } |
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index a4864d05ea92..b34c397909ef 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.131 2005/07/05 21:03:07 dwmw2 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 | ||
@@ -160,7 +161,7 @@ struct jffs2_full_dnode | |||
160 | */ | 161 | */ |
161 | struct jffs2_tmp_dnode_info | 162 | struct jffs2_tmp_dnode_info |
162 | { | 163 | { |
163 | struct jffs2_tmp_dnode_info *next; | 164 | struct rb_node rb; |
164 | struct jffs2_full_dnode *fn; | 165 | struct jffs2_full_dnode *fn; |
165 | uint32_t version; | 166 | uint32_t version; |
166 | }; | 167 | }; |
@@ -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) |
@@ -374,7 +387,7 @@ static inline struct jffs2_node_frag *frag_first(struct rb_root *root) | |||
374 | D2(void jffs2_print_frag_list(struct jffs2_inode_info *f)); | 387 | D2(void jffs2_print_frag_list(struct jffs2_inode_info *f)); |
375 | void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list); | 388 | void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list); |
376 | int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | 389 | int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f, |
377 | struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp, | 390 | struct rb_root *tnp, struct jffs2_full_dirent **fdp, |
378 | uint32_t *highest_version, uint32_t *latest_mctime, | 391 | uint32_t *highest_version, uint32_t *latest_mctime, |
379 | uint32_t *mctime_ver); | 392 | uint32_t *mctime_ver); |
380 | void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state); | 393 | void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state); |
@@ -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..7bf72e012c94 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h | |||
@@ -7,41 +7,24 @@ | |||
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.57 2005/07/06 12:13:09 dwmw2 Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #ifndef __JFFS2_OS_LINUX_H__ | 14 | #ifndef __JFFS2_OS_LINUX_H__ |
15 | #define __JFFS2_OS_LINUX_H__ | 15 | #define __JFFS2_OS_LINUX_H__ |
16 | #include <linux/version.h> | ||
17 | 16 | ||
18 | /* JFFS2 uses Linux mode bits natively -- no need for conversion */ | 17 | /* JFFS2 uses Linux mode bits natively -- no need for conversion */ |
19 | #define os_to_jffs2_mode(x) (x) | 18 | #define os_to_jffs2_mode(x) (x) |
20 | #define jffs2_to_os_mode(x) (x) | 19 | #define jffs2_to_os_mode(x) (x) |
21 | 20 | ||
22 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,73) | ||
23 | #define kstatfs statfs | ||
24 | #endif | ||
25 | |||
26 | struct kstatfs; | 21 | struct kstatfs; |
27 | struct kvec; | 22 | struct kvec; |
28 | 23 | ||
29 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2) | ||
30 | #define JFFS2_INODE_INFO(i) (list_entry(i, struct jffs2_inode_info, vfs_inode)) | 24 | #define JFFS2_INODE_INFO(i) (list_entry(i, struct jffs2_inode_info, vfs_inode)) |
31 | #define OFNI_EDONI_2SFFJ(f) (&(f)->vfs_inode) | 25 | #define OFNI_EDONI_2SFFJ(f) (&(f)->vfs_inode) |
32 | #define JFFS2_SB_INFO(sb) (sb->s_fs_info) | 26 | #define JFFS2_SB_INFO(sb) (sb->s_fs_info) |
33 | #define OFNI_BS_2SFFJ(c) ((struct super_block *)c->os_priv) | 27 | #define OFNI_BS_2SFFJ(c) ((struct super_block *)c->os_priv) |
34 | #elif defined(JFFS2_OUT_OF_KERNEL) | ||
35 | #define JFFS2_INODE_INFO(i) ((struct jffs2_inode_info *) &(i)->u) | ||
36 | #define OFNI_EDONI_2SFFJ(f) ((struct inode *) ( ((char *)f) - ((char *)(&((struct inode *)NULL)->u)) ) ) | ||
37 | #define JFFS2_SB_INFO(sb) ((struct jffs2_sb_info *) &(sb)->u) | ||
38 | #define OFNI_BS_2SFFJ(c) ((struct super_block *) ( ((char *)c) - ((char *)(&((struct super_block *)NULL)->u)) ) ) | ||
39 | #else | ||
40 | #define JFFS2_INODE_INFO(i) (&i->u.jffs2_i) | ||
41 | #define OFNI_EDONI_2SFFJ(f) ((struct inode *) ( ((char *)f) - ((char *)(&((struct inode *)NULL)->u)) ) ) | ||
42 | #define JFFS2_SB_INFO(sb) (&sb->u.jffs2_sb) | ||
43 | #define OFNI_BS_2SFFJ(c) ((struct super_block *) ( ((char *)c) - ((char *)(&((struct super_block *)NULL)->u)) ) ) | ||
44 | #endif | ||
45 | 28 | ||
46 | 29 | ||
47 | #define JFFS2_F_I_SIZE(f) (OFNI_EDONI_2SFFJ(f)->i_size) | 30 | #define JFFS2_F_I_SIZE(f) (OFNI_EDONI_2SFFJ(f)->i_size) |
@@ -49,28 +32,14 @@ struct kvec; | |||
49 | #define JFFS2_F_I_UID(f) (OFNI_EDONI_2SFFJ(f)->i_uid) | 32 | #define JFFS2_F_I_UID(f) (OFNI_EDONI_2SFFJ(f)->i_uid) |
50 | #define JFFS2_F_I_GID(f) (OFNI_EDONI_2SFFJ(f)->i_gid) | 33 | #define JFFS2_F_I_GID(f) (OFNI_EDONI_2SFFJ(f)->i_gid) |
51 | 34 | ||
52 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,1) | ||
53 | #define JFFS2_F_I_RDEV_MIN(f) (iminor(OFNI_EDONI_2SFFJ(f))) | 35 | #define JFFS2_F_I_RDEV_MIN(f) (iminor(OFNI_EDONI_2SFFJ(f))) |
54 | #define JFFS2_F_I_RDEV_MAJ(f) (imajor(OFNI_EDONI_2SFFJ(f))) | 36 | #define JFFS2_F_I_RDEV_MAJ(f) (imajor(OFNI_EDONI_2SFFJ(f))) |
55 | #else | ||
56 | #define JFFS2_F_I_RDEV_MIN(f) (MINOR(to_kdev_t(OFNI_EDONI_2SFFJ(f)->i_rdev))) | ||
57 | #define JFFS2_F_I_RDEV_MAJ(f) (MAJOR(to_kdev_t(OFNI_EDONI_2SFFJ(f)->i_rdev))) | ||
58 | #endif | ||
59 | 37 | ||
60 | /* Urgh. The things we do to keep the 2.4 build working */ | ||
61 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,47) | ||
62 | #define ITIME(sec) ((struct timespec){sec, 0}) | 38 | #define ITIME(sec) ((struct timespec){sec, 0}) |
63 | #define I_SEC(tv) ((tv).tv_sec) | 39 | #define I_SEC(tv) ((tv).tv_sec) |
64 | #define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime.tv_sec) | 40 | #define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime.tv_sec) |
65 | #define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime.tv_sec) | 41 | #define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime.tv_sec) |
66 | #define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime.tv_sec) | 42 | #define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime.tv_sec) |
67 | #else | ||
68 | #define ITIME(x) (x) | ||
69 | #define I_SEC(x) (x) | ||
70 | #define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime) | ||
71 | #define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime) | ||
72 | #define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime) | ||
73 | #endif | ||
74 | 43 | ||
75 | #define sleep_on_spinunlock(wq, s) \ | 44 | #define sleep_on_spinunlock(wq, s) \ |
76 | do { \ | 45 | do { \ |
@@ -84,23 +53,21 @@ struct kvec; | |||
84 | 53 | ||
85 | static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) | 54 | static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) |
86 | { | 55 | { |
87 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2) | ||
88 | f->highest_version = 0; | 56 | f->highest_version = 0; |
89 | f->fragtree = RB_ROOT; | 57 | f->fragtree = RB_ROOT; |
90 | f->metadata = NULL; | 58 | f->metadata = NULL; |
91 | f->dents = NULL; | 59 | f->dents = NULL; |
92 | f->flags = 0; | 60 | f->flags = 0; |
93 | f->usercompr = 0; | 61 | f->usercompr = 0; |
94 | #else | ||
95 | memset(f, 0, sizeof(*f)); | ||
96 | init_MUTEX_LOCKED(&f->sem); | ||
97 | #endif | ||
98 | } | 62 | } |
99 | 63 | ||
64 | |||
100 | #define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY) | 65 | #define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY) |
101 | 66 | ||
102 | #if (!defined CONFIG_JFFS2_FS_NAND && !defined CONFIG_JFFS2_FS_NOR_ECC) | 67 | #ifndef CONFIG_JFFS2_FS_WRITEBUFFER |
68 | #define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) ) | ||
103 | #define jffs2_can_mark_obsolete(c) (1) | 69 | #define jffs2_can_mark_obsolete(c) (1) |
70 | #define jffs2_is_writebuffered(c) (0) | ||
104 | #define jffs2_cleanmarker_oob(c) (0) | 71 | #define jffs2_cleanmarker_oob(c) (0) |
105 | #define jffs2_write_nand_cleanmarker(c,jeb) (-EIO) | 72 | #define jffs2_write_nand_cleanmarker(c,jeb) (-EIO) |
106 | 73 | ||
@@ -116,11 +83,14 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) | |||
116 | #define jffs2_wbuf_timeout NULL | 83 | #define jffs2_wbuf_timeout NULL |
117 | #define jffs2_wbuf_process NULL | 84 | #define jffs2_wbuf_process NULL |
118 | #define jffs2_nor_ecc(c) (0) | 85 | #define jffs2_nor_ecc(c) (0) |
86 | #define jffs2_dataflash(c) (0) | ||
119 | #define jffs2_nor_ecc_flash_setup(c) (0) | 87 | #define jffs2_nor_ecc_flash_setup(c) (0) |
120 | #define jffs2_nor_ecc_flash_cleanup(c) do {} while (0) | 88 | #define jffs2_nor_ecc_flash_cleanup(c) do {} while (0) |
121 | 89 | ||
122 | #else /* NAND and/or ECC'd NOR support present */ | 90 | #else /* NAND and/or ECC'd NOR support present */ |
123 | 91 | ||
92 | #define jffs2_is_writebuffered(c) (c->wbuf != NULL) | ||
93 | #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) | 94 | #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) | 95 | #define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH) |
126 | 96 | ||
@@ -142,16 +112,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); | 112 | int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c); |
143 | int jffs2_nand_flash_setup(struct jffs2_sb_info *c); | 113 | int jffs2_nand_flash_setup(struct jffs2_sb_info *c); |
144 | void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c); | 114 | void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c); |
145 | #ifdef CONFIG_JFFS2_FS_NOR_ECC | 115 | |
146 | #define jffs2_nor_ecc(c) (c->mtd->type == MTD_NORFLASH && (c->mtd->flags & MTD_ECC)) | 116 | #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); | 117 | int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c); |
148 | void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c); | 118 | void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c); |
149 | #else | 119 | |
150 | #define jffs2_nor_ecc(c) (0) | 120 | #define jffs2_dataflash(c) (c->mtd->type == MTD_DATAFLASH) |
151 | #define jffs2_nor_ecc_flash_setup(c) (0) | 121 | int jffs2_dataflash_setup(struct jffs2_sb_info *c); |
152 | #define jffs2_nor_ecc_flash_cleanup(c) do {} while (0) | 122 | void jffs2_dataflash_cleanup(struct jffs2_sb_info *c); |
153 | #endif /* NOR ECC */ | 123 | |
154 | #endif /* NAND */ | 124 | #endif /* WRITEBUFFER */ |
155 | 125 | ||
156 | /* erase.c */ | 126 | /* erase.c */ |
157 | static inline void jffs2_erase_pending_trigger(struct jffs2_sb_info *c) | 127 | 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..081656c1d49e 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.120 2005/07/05 21:03:07 dwmw2 Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -500,7 +500,9 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
500 | struct jffs2_inode_info *f, | 500 | struct jffs2_inode_info *f, |
501 | struct jffs2_raw_inode *latest_node) | 501 | struct jffs2_raw_inode *latest_node) |
502 | { | 502 | { |
503 | struct jffs2_tmp_dnode_info *tn_list, *tn; | 503 | struct jffs2_tmp_dnode_info *tn = NULL; |
504 | struct rb_root tn_list; | ||
505 | struct rb_node *rb, *repl_rb; | ||
504 | struct jffs2_full_dirent *fd_list; | 506 | struct jffs2_full_dirent *fd_list; |
505 | struct jffs2_full_dnode *fn = NULL; | 507 | struct jffs2_full_dnode *fn = NULL; |
506 | uint32_t crc; | 508 | uint32_t crc; |
@@ -522,9 +524,10 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
522 | } | 524 | } |
523 | f->dents = fd_list; | 525 | f->dents = fd_list; |
524 | 526 | ||
525 | while (tn_list) { | 527 | rb = rb_first(&tn_list); |
526 | tn = tn_list; | ||
527 | 528 | ||
529 | while (rb) { | ||
530 | tn = rb_entry(rb, struct jffs2_tmp_dnode_info, rb); | ||
528 | fn = tn->fn; | 531 | fn = tn->fn; |
529 | 532 | ||
530 | if (f->metadata) { | 533 | if (f->metadata) { |
@@ -556,7 +559,30 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
556 | mdata_ver = tn->version; | 559 | mdata_ver = tn->version; |
557 | } | 560 | } |
558 | next_tn: | 561 | next_tn: |
559 | tn_list = tn->next; | 562 | BUG_ON(rb->rb_left); |
563 | repl_rb = NULL; | ||
564 | if (rb->rb_parent && rb->rb_parent->rb_left == rb) { | ||
565 | /* We were then left-hand child of our parent. We need | ||
566 | to move our own right-hand child into our place. */ | ||
567 | repl_rb = rb->rb_right; | ||
568 | if (repl_rb) | ||
569 | repl_rb->rb_parent = rb->rb_parent; | ||
570 | } else | ||
571 | repl_rb = NULL; | ||
572 | |||
573 | rb = rb_next(rb); | ||
574 | |||
575 | /* Remove the spent tn from the tree; don't bother rebalancing | ||
576 | but put our right-hand child in our own place. */ | ||
577 | if (tn->rb.rb_parent) { | ||
578 | if (tn->rb.rb_parent->rb_left == &tn->rb) | ||
579 | tn->rb.rb_parent->rb_left = repl_rb; | ||
580 | else if (tn->rb.rb_parent->rb_right == &tn->rb) | ||
581 | tn->rb.rb_parent->rb_right = repl_rb; | ||
582 | else BUG(); | ||
583 | } else if (tn->rb.rb_right) | ||
584 | tn->rb.rb_right->rb_parent = NULL; | ||
585 | |||
560 | jffs2_free_tmp_dnode_info(tn); | 586 | jffs2_free_tmp_dnode_info(tn); |
561 | } | 587 | } |
562 | D1(jffs2_sanitycheck_fragtree(f)); | 588 | D1(jffs2_sanitycheck_fragtree(f)); |
@@ -623,6 +649,40 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
623 | case. */ | 649 | case. */ |
624 | if (!je32_to_cpu(latest_node->isize)) | 650 | if (!je32_to_cpu(latest_node->isize)) |
625 | latest_node->isize = latest_node->dsize; | 651 | latest_node->isize = latest_node->dsize; |
652 | |||
653 | if (f->inocache->state != INO_STATE_CHECKING) { | ||
654 | /* Symlink's inode data is the target path. Read it and | ||
655 | * keep in RAM to facilitate quick follow symlink operation. | ||
656 | * We use f->dents field to store the target path, which | ||
657 | * is somewhat ugly. */ | ||
658 | f->dents = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL); | ||
659 | if (!f->dents) { | ||
660 | printk(KERN_WARNING "Can't allocate %d bytes of memory " | ||
661 | "for the symlink target path cache\n", | ||
662 | je32_to_cpu(latest_node->csize)); | ||
663 | up(&f->sem); | ||
664 | jffs2_do_clear_inode(c, f); | ||
665 | return -ENOMEM; | ||
666 | } | ||
667 | |||
668 | ret = jffs2_flash_read(c, ref_offset(fn->raw) + sizeof(*latest_node), | ||
669 | je32_to_cpu(latest_node->csize), &retlen, (char *)f->dents); | ||
670 | |||
671 | if (ret || retlen != je32_to_cpu(latest_node->csize)) { | ||
672 | if (retlen != je32_to_cpu(latest_node->csize)) | ||
673 | ret = -EIO; | ||
674 | kfree(f->dents); | ||
675 | f->dents = NULL; | ||
676 | up(&f->sem); | ||
677 | jffs2_do_clear_inode(c, f); | ||
678 | return -ret; | ||
679 | } | ||
680 | |||
681 | ((char *)f->dents)[je32_to_cpu(latest_node->csize)] = '\0'; | ||
682 | D1(printk(KERN_DEBUG "jffs2_do_read_inode(): symlink's target '%s' cached\n", | ||
683 | (char *)f->dents)); | ||
684 | } | ||
685 | |||
626 | /* fall through... */ | 686 | /* fall through... */ |
627 | 687 | ||
628 | case S_IFBLK: | 688 | case S_IFBLK: |
@@ -672,6 +732,9 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) | |||
672 | down(&f->sem); | 732 | down(&f->sem); |
673 | deleted = f->inocache && !f->inocache->nlink; | 733 | deleted = f->inocache && !f->inocache->nlink; |
674 | 734 | ||
735 | if (f->inocache && f->inocache->state != INO_STATE_CHECKING) | ||
736 | jffs2_set_inocache_state(c, f->inocache, INO_STATE_CLEARING); | ||
737 | |||
675 | if (f->metadata) { | 738 | if (f->metadata) { |
676 | if (deleted) | 739 | if (deleted) |
677 | jffs2_mark_node_obsolete(c, f->metadata->raw); | 740 | jffs2_mark_node_obsolete(c, f->metadata->raw); |
@@ -680,16 +743,27 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) | |||
680 | 743 | ||
681 | jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL); | 744 | jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL); |
682 | 745 | ||
683 | fds = f->dents; | 746 | /* For symlink inodes we us f->dents to store the target path name */ |
747 | if (S_ISLNK(OFNI_EDONI_2SFFJ(f)->i_mode)) { | ||
748 | if (f->dents) { | ||
749 | kfree(f->dents); | ||
750 | f->dents = NULL; | ||
751 | } | ||
752 | } else { | ||
753 | fds = f->dents; | ||
684 | 754 | ||
685 | while(fds) { | 755 | while(fds) { |
686 | fd = fds; | 756 | fd = fds; |
687 | fds = fd->next; | 757 | fds = fd->next; |
688 | jffs2_free_full_dirent(fd); | 758 | jffs2_free_full_dirent(fd); |
759 | } | ||
689 | } | 760 | } |
690 | 761 | ||
691 | if (f->inocache && f->inocache->state != INO_STATE_CHECKING) | 762 | if (f->inocache && f->inocache->state != INO_STATE_CHECKING) { |
692 | jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); | 763 | jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); |
764 | if (f->inocache->nodes == (void *)f->inocache) | ||
765 | jffs2_del_ino_cache(c, f->inocache); | ||
766 | } | ||
693 | 767 | ||
694 | up(&f->sem); | 768 | up(&f->sem); |
695 | } | 769 | } |
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--; |