diff options
Diffstat (limited to 'fs/jffs2')
-rw-r--r-- | fs/jffs2/Kconfig | 188 | ||||
-rw-r--r-- | fs/jffs2/background.c | 10 | ||||
-rw-r--r-- | fs/jffs2/compr.c | 4 | ||||
-rw-r--r-- | fs/jffs2/compr_lzo.c | 15 | ||||
-rw-r--r-- | fs/jffs2/dir.c | 9 | ||||
-rw-r--r-- | fs/jffs2/erase.c | 4 | ||||
-rw-r--r-- | fs/jffs2/fs.c | 6 | ||||
-rw-r--r-- | fs/jffs2/nodemgmt.c | 6 | ||||
-rw-r--r-- | fs/jffs2/super.c | 48 | ||||
-rw-r--r-- | fs/jffs2/wbuf.c | 5 |
10 files changed, 269 insertions, 26 deletions
diff --git a/fs/jffs2/Kconfig b/fs/jffs2/Kconfig new file mode 100644 index 000000000000..6ae169cd8faa --- /dev/null +++ b/fs/jffs2/Kconfig | |||
@@ -0,0 +1,188 @@ | |||
1 | config JFFS2_FS | ||
2 | tristate "Journalling Flash File System v2 (JFFS2) support" | ||
3 | select CRC32 | ||
4 | depends on MTD | ||
5 | help | ||
6 | JFFS2 is the second generation of the Journalling Flash File System | ||
7 | for use on diskless embedded devices. It provides improved wear | ||
8 | levelling, compression and support for hard links. You cannot use | ||
9 | this on normal block devices, only on 'MTD' devices. | ||
10 | |||
11 | Further information on the design and implementation of JFFS2 is | ||
12 | available at <http://sources.redhat.com/jffs2/>. | ||
13 | |||
14 | config JFFS2_FS_DEBUG | ||
15 | int "JFFS2 debugging verbosity (0 = quiet, 2 = noisy)" | ||
16 | depends on JFFS2_FS | ||
17 | default "0" | ||
18 | help | ||
19 | This controls the amount of debugging messages produced by the JFFS2 | ||
20 | code. Set it to zero for use in production systems. For evaluation, | ||
21 | testing and debugging, it's advisable to set it to one. This will | ||
22 | enable a few assertions and will print debugging messages at the | ||
23 | KERN_DEBUG loglevel, where they won't normally be visible. Level 2 | ||
24 | is unlikely to be useful - it enables extra debugging in certain | ||
25 | areas which at one point needed debugging, but when the bugs were | ||
26 | located and fixed, the detailed messages were relegated to level 2. | ||
27 | |||
28 | If reporting bugs, please try to have available a full dump of the | ||
29 | messages at debug level 1 while the misbehaviour was occurring. | ||
30 | |||
31 | config JFFS2_FS_WRITEBUFFER | ||
32 | bool "JFFS2 write-buffering support" | ||
33 | depends on JFFS2_FS | ||
34 | default y | ||
35 | help | ||
36 | This enables the write-buffering support in JFFS2. | ||
37 | |||
38 | This functionality is required to support JFFS2 on the following | ||
39 | types of flash devices: | ||
40 | - NAND flash | ||
41 | - NOR flash with transparent ECC | ||
42 | - DataFlash | ||
43 | |||
44 | config JFFS2_FS_WBUF_VERIFY | ||
45 | bool "Verify JFFS2 write-buffer reads" | ||
46 | depends on JFFS2_FS_WRITEBUFFER | ||
47 | default n | ||
48 | help | ||
49 | This causes JFFS2 to read back every page written through the | ||
50 | write-buffer, and check for errors. | ||
51 | |||
52 | config JFFS2_SUMMARY | ||
53 | bool "JFFS2 summary support (EXPERIMENTAL)" | ||
54 | depends on JFFS2_FS && EXPERIMENTAL | ||
55 | default n | ||
56 | help | ||
57 | This feature makes it possible to use summary information | ||
58 | for faster filesystem mount. | ||
59 | |||
60 | The summary information can be inserted into a filesystem image | ||
61 | by the utility 'sumtool'. | ||
62 | |||
63 | If unsure, say 'N'. | ||
64 | |||
65 | config JFFS2_FS_XATTR | ||
66 | bool "JFFS2 XATTR support (EXPERIMENTAL)" | ||
67 | depends on JFFS2_FS && EXPERIMENTAL | ||
68 | default n | ||
69 | help | ||
70 | Extended attributes are name:value pairs associated with inodes by | ||
71 | the kernel or by users (see the attr(5) manual page, or visit | ||
72 | <http://acl.bestbits.at/> for details). | ||
73 | |||
74 | If unsure, say N. | ||
75 | |||
76 | config JFFS2_FS_POSIX_ACL | ||
77 | bool "JFFS2 POSIX Access Control Lists" | ||
78 | depends on JFFS2_FS_XATTR | ||
79 | default y | ||
80 | select FS_POSIX_ACL | ||
81 | help | ||
82 | Posix Access Control Lists (ACLs) support permissions for users and | ||
83 | groups beyond the owner/group/world scheme. | ||
84 | |||
85 | To learn more about Access Control Lists, visit the Posix ACLs for | ||
86 | Linux website <http://acl.bestbits.at/>. | ||
87 | |||
88 | If you don't know what Access Control Lists are, say N | ||
89 | |||
90 | config JFFS2_FS_SECURITY | ||
91 | bool "JFFS2 Security Labels" | ||
92 | depends on JFFS2_FS_XATTR | ||
93 | default y | ||
94 | help | ||
95 | Security labels support alternative access control models | ||
96 | implemented by security modules like SELinux. This option | ||
97 | enables an extended attribute handler for file security | ||
98 | labels in the jffs2 filesystem. | ||
99 | |||
100 | If you are not using a security module that requires using | ||
101 | extended attributes for file security labels, say N. | ||
102 | |||
103 | config JFFS2_COMPRESSION_OPTIONS | ||
104 | bool "Advanced compression options for JFFS2" | ||
105 | depends on JFFS2_FS | ||
106 | default n | ||
107 | help | ||
108 | Enabling this option allows you to explicitly choose which | ||
109 | compression modules, if any, are enabled in JFFS2. Removing | ||
110 | compressors can mean you cannot read existing file systems, | ||
111 | and enabling experimental compressors can mean that you | ||
112 | write a file system which cannot be read by a standard kernel. | ||
113 | |||
114 | If unsure, you should _definitely_ say 'N'. | ||
115 | |||
116 | config JFFS2_ZLIB | ||
117 | bool "JFFS2 ZLIB compression support" if JFFS2_COMPRESSION_OPTIONS | ||
118 | select ZLIB_INFLATE | ||
119 | select ZLIB_DEFLATE | ||
120 | depends on JFFS2_FS | ||
121 | default y | ||
122 | help | ||
123 | Zlib is designed to be a free, general-purpose, legally unencumbered, | ||
124 | lossless data-compression library for use on virtually any computer | ||
125 | hardware and operating system. See <http://www.gzip.org/zlib/> for | ||
126 | further information. | ||
127 | |||
128 | Say 'Y' if unsure. | ||
129 | |||
130 | config JFFS2_LZO | ||
131 | bool "JFFS2 LZO compression support" if JFFS2_COMPRESSION_OPTIONS | ||
132 | select LZO_COMPRESS | ||
133 | select LZO_DECOMPRESS | ||
134 | depends on JFFS2_FS | ||
135 | default n | ||
136 | help | ||
137 | minilzo-based compression. Generally works better than Zlib. | ||
138 | |||
139 | This feature was added in July, 2007. Say 'N' if you need | ||
140 | compatibility with older bootloaders or kernels. | ||
141 | |||
142 | config JFFS2_RTIME | ||
143 | bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS | ||
144 | depends on JFFS2_FS | ||
145 | default y | ||
146 | help | ||
147 | Rtime does manage to recompress already-compressed data. Say 'Y' if unsure. | ||
148 | |||
149 | config JFFS2_RUBIN | ||
150 | bool "JFFS2 RUBIN compression support" if JFFS2_COMPRESSION_OPTIONS | ||
151 | depends on JFFS2_FS | ||
152 | default n | ||
153 | help | ||
154 | RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure. | ||
155 | |||
156 | choice | ||
157 | prompt "JFFS2 default compression mode" if JFFS2_COMPRESSION_OPTIONS | ||
158 | default JFFS2_CMODE_PRIORITY | ||
159 | depends on JFFS2_FS | ||
160 | help | ||
161 | You can set here the default compression mode of JFFS2 from | ||
162 | the available compression modes. Don't touch if unsure. | ||
163 | |||
164 | config JFFS2_CMODE_NONE | ||
165 | bool "no compression" | ||
166 | help | ||
167 | Uses no compression. | ||
168 | |||
169 | config JFFS2_CMODE_PRIORITY | ||
170 | bool "priority" | ||
171 | help | ||
172 | Tries the compressors in a predefined order and chooses the first | ||
173 | successful one. | ||
174 | |||
175 | config JFFS2_CMODE_SIZE | ||
176 | bool "size (EXPERIMENTAL)" | ||
177 | help | ||
178 | Tries all compressors and chooses the one which has the smallest | ||
179 | result. | ||
180 | |||
181 | config JFFS2_CMODE_FAVOURLZO | ||
182 | bool "Favour LZO" | ||
183 | help | ||
184 | Tries all compressors and chooses the one which has the smallest | ||
185 | result but gives some preference to LZO (which has faster | ||
186 | decompression) at the expense of size. | ||
187 | |||
188 | endchoice | ||
diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index 8adebd3e43c6..3cceef4ad2b7 100644 --- a/fs/jffs2/background.c +++ b/fs/jffs2/background.c | |||
@@ -85,15 +85,15 @@ static int jffs2_garbage_collect_thread(void *_c) | |||
85 | for (;;) { | 85 | for (;;) { |
86 | allow_signal(SIGHUP); | 86 | allow_signal(SIGHUP); |
87 | again: | 87 | again: |
88 | spin_lock(&c->erase_completion_lock); | ||
88 | if (!jffs2_thread_should_wake(c)) { | 89 | if (!jffs2_thread_should_wake(c)) { |
89 | set_current_state (TASK_INTERRUPTIBLE); | 90 | set_current_state (TASK_INTERRUPTIBLE); |
91 | spin_unlock(&c->erase_completion_lock); | ||
90 | D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread sleeping...\n")); | 92 | D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread sleeping...\n")); |
91 | /* Yes, there's a race here; we checked jffs2_thread_should_wake() | ||
92 | before setting current->state to TASK_INTERRUPTIBLE. But it doesn't | ||
93 | matter - We don't care if we miss a wakeup, because the GC thread | ||
94 | is only an optimisation anyway. */ | ||
95 | schedule(); | 93 | schedule(); |
96 | } | 94 | } else |
95 | spin_unlock(&c->erase_completion_lock); | ||
96 | |||
97 | 97 | ||
98 | /* This thread is purely an optimisation. But if it runs when | 98 | /* This thread is purely an optimisation. But if it runs when |
99 | other things could be running, it actually makes things a | 99 | other things could be running, it actually makes things a |
diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c index 86739ee53b37..f25e70c1b51c 100644 --- a/fs/jffs2/compr.c +++ b/fs/jffs2/compr.c | |||
@@ -53,8 +53,8 @@ static int jffs2_is_best_compression(struct jffs2_compressor *this, | |||
53 | } | 53 | } |
54 | 54 | ||
55 | /* jffs2_compress: | 55 | /* jffs2_compress: |
56 | * @data: Pointer to uncompressed data | 56 | * @data_in: Pointer to uncompressed data |
57 | * @cdata: Pointer to returned pointer to buffer for compressed data | 57 | * @cpage_out: Pointer to returned pointer to buffer for compressed data |
58 | * @datalen: On entry, holds the amount of data available for compression. | 58 | * @datalen: On entry, holds the amount of data available for compression. |
59 | * On exit, expected to hold the amount of data actually compressed. | 59 | * On exit, expected to hold the amount of data actually compressed. |
60 | * @cdatalen: On entry, holds the amount of space available for compressed | 60 | * @cdatalen: On entry, holds the amount of space available for compressed |
diff --git a/fs/jffs2/compr_lzo.c b/fs/jffs2/compr_lzo.c index 47b045797e42..90cb60d09787 100644 --- a/fs/jffs2/compr_lzo.c +++ b/fs/jffs2/compr_lzo.c | |||
@@ -19,7 +19,7 @@ | |||
19 | 19 | ||
20 | static void *lzo_mem; | 20 | static void *lzo_mem; |
21 | static void *lzo_compress_buf; | 21 | static void *lzo_compress_buf; |
22 | static DEFINE_MUTEX(deflate_mutex); | 22 | static DEFINE_MUTEX(deflate_mutex); /* for lzo_mem and lzo_compress_buf */ |
23 | 23 | ||
24 | static void free_workspace(void) | 24 | static void free_workspace(void) |
25 | { | 25 | { |
@@ -49,18 +49,21 @@ static int jffs2_lzo_compress(unsigned char *data_in, unsigned char *cpage_out, | |||
49 | 49 | ||
50 | mutex_lock(&deflate_mutex); | 50 | mutex_lock(&deflate_mutex); |
51 | ret = lzo1x_1_compress(data_in, *sourcelen, lzo_compress_buf, &compress_size, lzo_mem); | 51 | ret = lzo1x_1_compress(data_in, *sourcelen, lzo_compress_buf, &compress_size, lzo_mem); |
52 | mutex_unlock(&deflate_mutex); | ||
53 | |||
54 | if (ret != LZO_E_OK) | 52 | if (ret != LZO_E_OK) |
55 | return -1; | 53 | goto fail; |
56 | 54 | ||
57 | if (compress_size > *dstlen) | 55 | if (compress_size > *dstlen) |
58 | return -1; | 56 | goto fail; |
59 | 57 | ||
60 | memcpy(cpage_out, lzo_compress_buf, compress_size); | 58 | memcpy(cpage_out, lzo_compress_buf, compress_size); |
61 | *dstlen = compress_size; | 59 | mutex_unlock(&deflate_mutex); |
62 | 60 | ||
61 | *dstlen = compress_size; | ||
63 | return 0; | 62 | return 0; |
63 | |||
64 | fail: | ||
65 | mutex_unlock(&deflate_mutex); | ||
66 | return -1; | ||
64 | } | 67 | } |
65 | 68 | ||
66 | static int jffs2_lzo_decompress(unsigned char *data_in, unsigned char *cpage_out, | 69 | static int jffs2_lzo_decompress(unsigned char *data_in, unsigned char *cpage_out, |
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index cd219ef55254..6f60cc910f4c 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c | |||
@@ -39,7 +39,8 @@ const struct file_operations jffs2_dir_operations = | |||
39 | .read = generic_read_dir, | 39 | .read = generic_read_dir, |
40 | .readdir = jffs2_readdir, | 40 | .readdir = jffs2_readdir, |
41 | .unlocked_ioctl=jffs2_ioctl, | 41 | .unlocked_ioctl=jffs2_ioctl, |
42 | .fsync = jffs2_fsync | 42 | .fsync = jffs2_fsync, |
43 | .llseek = generic_file_llseek, | ||
43 | }; | 44 | }; |
44 | 45 | ||
45 | 46 | ||
@@ -108,9 +109,7 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target, | |||
108 | } | 109 | } |
109 | } | 110 | } |
110 | 111 | ||
111 | d_add(target, inode); | 112 | return d_splice_alias(inode, target); |
112 | |||
113 | return NULL; | ||
114 | } | 113 | } |
115 | 114 | ||
116 | /***********************************************************************/ | 115 | /***********************************************************************/ |
@@ -311,7 +310,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
311 | /* FIXME: If you care. We'd need to use frags for the target | 310 | /* FIXME: If you care. We'd need to use frags for the target |
312 | if it grows much more than this */ | 311 | if it grows much more than this */ |
313 | if (targetlen > 254) | 312 | if (targetlen > 254) |
314 | return -EINVAL; | 313 | return -ENAMETOOLONG; |
315 | 314 | ||
316 | ri = jffs2_alloc_raw_inode(); | 315 | ri = jffs2_alloc_raw_inode(); |
317 | 316 | ||
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index dddb2a6c9e2c..259461b910af 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c | |||
@@ -68,7 +68,7 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, | |||
68 | instr->len = c->sector_size; | 68 | instr->len = c->sector_size; |
69 | instr->callback = jffs2_erase_callback; | 69 | instr->callback = jffs2_erase_callback; |
70 | instr->priv = (unsigned long)(&instr[1]); | 70 | instr->priv = (unsigned long)(&instr[1]); |
71 | instr->fail_addr = 0xffffffff; | 71 | instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; |
72 | 72 | ||
73 | ((struct erase_priv_struct *)instr->priv)->jeb = jeb; | 73 | ((struct erase_priv_struct *)instr->priv)->jeb = jeb; |
74 | ((struct erase_priv_struct *)instr->priv)->c = c; | 74 | ((struct erase_priv_struct *)instr->priv)->c = c; |
@@ -175,7 +175,7 @@ static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock | |||
175 | { | 175 | { |
176 | /* For NAND, if the failure did not occur at the device level for a | 176 | /* For NAND, if the failure did not occur at the device level for a |
177 | specific physical page, don't bother updating the bad block table. */ | 177 | specific physical page, don't bother updating the bad block table. */ |
178 | if (jffs2_cleanmarker_oob(c) && (bad_offset != 0xffffffff)) { | 178 | if (jffs2_cleanmarker_oob(c) && (bad_offset != MTD_FAIL_ADDR_UNKNOWN)) { |
179 | /* We had a device-level failure to erase. Let's see if we've | 179 | /* We had a device-level failure to erase. Let's see if we've |
180 | failed too many times. */ | 180 | failed too many times. */ |
181 | if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) { | 181 | if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) { |
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 086c43830221..249305d65d5b 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c | |||
@@ -207,6 +207,8 @@ int jffs2_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
207 | buf->f_files = 0; | 207 | buf->f_files = 0; |
208 | buf->f_ffree = 0; | 208 | buf->f_ffree = 0; |
209 | buf->f_namelen = JFFS2_MAX_NAME_LEN; | 209 | buf->f_namelen = JFFS2_MAX_NAME_LEN; |
210 | buf->f_fsid.val[0] = JFFS2_SUPER_MAGIC; | ||
211 | buf->f_fsid.val[1] = c->mtd->index; | ||
210 | 212 | ||
211 | spin_lock(&c->erase_completion_lock); | 213 | spin_lock(&c->erase_completion_lock); |
212 | avail = c->dirty_size + c->free_size; | 214 | avail = c->dirty_size + c->free_size; |
@@ -440,14 +442,14 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i | |||
440 | 442 | ||
441 | memset(ri, 0, sizeof(*ri)); | 443 | memset(ri, 0, sizeof(*ri)); |
442 | /* Set OS-specific defaults for new inodes */ | 444 | /* Set OS-specific defaults for new inodes */ |
443 | ri->uid = cpu_to_je16(current->fsuid); | 445 | ri->uid = cpu_to_je16(current_fsuid()); |
444 | 446 | ||
445 | if (dir_i->i_mode & S_ISGID) { | 447 | if (dir_i->i_mode & S_ISGID) { |
446 | ri->gid = cpu_to_je16(dir_i->i_gid); | 448 | ri->gid = cpu_to_je16(dir_i->i_gid); |
447 | if (S_ISDIR(mode)) | 449 | if (S_ISDIR(mode)) |
448 | mode |= S_ISGID; | 450 | mode |= S_ISGID; |
449 | } else { | 451 | } else { |
450 | ri->gid = cpu_to_je16(current->fsgid); | 452 | ri->gid = cpu_to_je16(current_fsgid()); |
451 | } | 453 | } |
452 | 454 | ||
453 | /* POSIX ACLs have to be processed now, at least partly. | 455 | /* POSIX ACLs have to be processed now, at least partly. |
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index a9bf9603c1ba..21a052915aa9 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c | |||
@@ -261,6 +261,12 @@ static int jffs2_find_nextblock(struct jffs2_sb_info *c) | |||
261 | 261 | ||
262 | jffs2_sum_reset_collected(c->summary); /* reset collected summary */ | 262 | jffs2_sum_reset_collected(c->summary); /* reset collected summary */ |
263 | 263 | ||
264 | #ifdef CONFIG_JFFS2_FS_WRITEBUFFER | ||
265 | /* adjust write buffer offset, else we get a non contiguous write bug */ | ||
266 | if (!(c->wbuf_ofs % c->sector_size) && !c->wbuf_len) | ||
267 | c->wbuf_ofs = 0xffffffff; | ||
268 | #endif | ||
269 | |||
264 | D1(printk(KERN_DEBUG "jffs2_find_nextblock(): new nextblock = 0x%08x\n", c->nextblock->offset)); | 270 | D1(printk(KERN_DEBUG "jffs2_find_nextblock(): new nextblock = 0x%08x\n", c->nextblock->offset)); |
265 | 271 | ||
266 | return 0; | 272 | return 0; |
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index efd401257ed9..4c4e18c54a51 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/mtd/super.h> | 22 | #include <linux/mtd/super.h> |
23 | #include <linux/ctype.h> | 23 | #include <linux/ctype.h> |
24 | #include <linux/namei.h> | 24 | #include <linux/namei.h> |
25 | #include <linux/exportfs.h> | ||
25 | #include "compr.h" | 26 | #include "compr.h" |
26 | #include "nodelist.h" | 27 | #include "nodelist.h" |
27 | 28 | ||
@@ -62,6 +63,52 @@ static int jffs2_sync_fs(struct super_block *sb, int wait) | |||
62 | return 0; | 63 | return 0; |
63 | } | 64 | } |
64 | 65 | ||
66 | static struct inode *jffs2_nfs_get_inode(struct super_block *sb, uint64_t ino, | ||
67 | uint32_t generation) | ||
68 | { | ||
69 | /* We don't care about i_generation. We'll destroy the flash | ||
70 | before we start re-using inode numbers anyway. And even | ||
71 | if that wasn't true, we'd have other problems...*/ | ||
72 | return jffs2_iget(sb, ino); | ||
73 | } | ||
74 | |||
75 | static struct dentry *jffs2_fh_to_dentry(struct super_block *sb, struct fid *fid, | ||
76 | int fh_len, int fh_type) | ||
77 | { | ||
78 | return generic_fh_to_dentry(sb, fid, fh_len, fh_type, | ||
79 | jffs2_nfs_get_inode); | ||
80 | } | ||
81 | |||
82 | static struct dentry *jffs2_fh_to_parent(struct super_block *sb, struct fid *fid, | ||
83 | int fh_len, int fh_type) | ||
84 | { | ||
85 | return generic_fh_to_parent(sb, fid, fh_len, fh_type, | ||
86 | jffs2_nfs_get_inode); | ||
87 | } | ||
88 | |||
89 | static struct dentry *jffs2_get_parent(struct dentry *child) | ||
90 | { | ||
91 | struct jffs2_inode_info *f; | ||
92 | uint32_t pino; | ||
93 | |||
94 | BUG_ON(!S_ISDIR(child->d_inode->i_mode)); | ||
95 | |||
96 | f = JFFS2_INODE_INFO(child->d_inode); | ||
97 | |||
98 | pino = f->inocache->pino_nlink; | ||
99 | |||
100 | JFFS2_DEBUG("Parent of directory ino #%u is #%u\n", | ||
101 | f->inocache->ino, pino); | ||
102 | |||
103 | return d_obtain_alias(jffs2_iget(child->d_inode->i_sb, pino)); | ||
104 | } | ||
105 | |||
106 | static struct export_operations jffs2_export_ops = { | ||
107 | .get_parent = jffs2_get_parent, | ||
108 | .fh_to_dentry = jffs2_fh_to_dentry, | ||
109 | .fh_to_parent = jffs2_fh_to_parent, | ||
110 | }; | ||
111 | |||
65 | static const struct super_operations jffs2_super_operations = | 112 | static const struct super_operations jffs2_super_operations = |
66 | { | 113 | { |
67 | .alloc_inode = jffs2_alloc_inode, | 114 | .alloc_inode = jffs2_alloc_inode, |
@@ -104,6 +151,7 @@ static int jffs2_fill_super(struct super_block *sb, void *data, int silent) | |||
104 | spin_lock_init(&c->inocache_lock); | 151 | spin_lock_init(&c->inocache_lock); |
105 | 152 | ||
106 | sb->s_op = &jffs2_super_operations; | 153 | sb->s_op = &jffs2_super_operations; |
154 | sb->s_export_op = &jffs2_export_ops; | ||
107 | sb->s_flags = sb->s_flags | MS_NOATIME; | 155 | sb->s_flags = sb->s_flags | MS_NOATIME; |
108 | sb->s_xattr = jffs2_xattr_handlers; | 156 | sb->s_xattr = jffs2_xattr_handlers; |
109 | #ifdef CONFIG_JFFS2_FS_POSIX_ACL | 157 | #ifdef CONFIG_JFFS2_FS_POSIX_ACL |
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 0e78b00035e4..d9a721e6db70 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c | |||
@@ -679,10 +679,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) | |||
679 | 679 | ||
680 | memset(c->wbuf,0xff,c->wbuf_pagesize); | 680 | memset(c->wbuf,0xff,c->wbuf_pagesize); |
681 | /* adjust write buffer offset, else we get a non contiguous write bug */ | 681 | /* adjust write buffer offset, else we get a non contiguous write bug */ |
682 | if (SECTOR_ADDR(c->wbuf_ofs) == SECTOR_ADDR(c->wbuf_ofs+c->wbuf_pagesize)) | 682 | c->wbuf_ofs += c->wbuf_pagesize; |
683 | c->wbuf_ofs += c->wbuf_pagesize; | ||
684 | else | ||
685 | c->wbuf_ofs = 0xffffffff; | ||
686 | c->wbuf_len = 0; | 683 | c->wbuf_len = 0; |
687 | return 0; | 684 | return 0; |
688 | } | 685 | } |