diff options
Diffstat (limited to 'fs/jffs2/write.c')
-rw-r--r-- | fs/jffs2/write.c | 708 |
1 files changed, 708 insertions, 0 deletions
diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c new file mode 100644 index 000000000000..80a5db542629 --- /dev/null +++ b/fs/jffs2/write.c | |||
@@ -0,0 +1,708 @@ | |||
1 | /* | ||
2 | * JFFS2 -- Journalling Flash File System, Version 2. | ||
3 | * | ||
4 | * Copyright (C) 2001-2003 Red Hat, Inc. | ||
5 | * | ||
6 | * Created by David Woodhouse <dwmw2@infradead.org> | ||
7 | * | ||
8 | * For licensing information, see the file 'LICENCE' in this directory. | ||
9 | * | ||
10 | * $Id: write.c,v 1.87 2004/11/16 20:36:12 dwmw2 Exp $ | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/fs.h> | ||
16 | #include <linux/crc32.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/pagemap.h> | ||
19 | #include <linux/mtd/mtd.h> | ||
20 | #include "nodelist.h" | ||
21 | #include "compr.h" | ||
22 | |||
23 | |||
24 | int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t mode, struct jffs2_raw_inode *ri) | ||
25 | { | ||
26 | struct jffs2_inode_cache *ic; | ||
27 | |||
28 | ic = jffs2_alloc_inode_cache(); | ||
29 | if (!ic) { | ||
30 | return -ENOMEM; | ||
31 | } | ||
32 | |||
33 | memset(ic, 0, sizeof(*ic)); | ||
34 | |||
35 | f->inocache = ic; | ||
36 | f->inocache->nlink = 1; | ||
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; | ||
40 | |||
41 | ri->ino = cpu_to_je32(f->inocache->ino); | ||
42 | |||
43 | D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino)); | ||
44 | jffs2_add_ino_cache(c, f->inocache); | ||
45 | |||
46 | ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | ||
47 | ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); | ||
48 | ri->totlen = cpu_to_je32(PAD(sizeof(*ri))); | ||
49 | ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); | ||
50 | ri->mode = cpu_to_jemode(mode); | ||
51 | |||
52 | f->highest_version = 1; | ||
53 | ri->version = cpu_to_je32(f->highest_version); | ||
54 | |||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | #if CONFIG_JFFS2_FS_DEBUG > 0 | ||
59 | static void writecheck(struct jffs2_sb_info *c, uint32_t ofs) | ||
60 | { | ||
61 | unsigned char buf[16]; | ||
62 | size_t retlen; | ||
63 | int ret, i; | ||
64 | |||
65 | ret = jffs2_flash_read(c, ofs, 16, &retlen, buf); | ||
66 | if (ret || (retlen != 16)) { | ||
67 | D1(printk(KERN_DEBUG "read failed or short in writecheck(). ret %d, retlen %zd\n", ret, retlen)); | ||
68 | return; | ||
69 | } | ||
70 | ret = 0; | ||
71 | for (i=0; i<16; i++) { | ||
72 | if (buf[i] != 0xff) | ||
73 | ret = 1; | ||
74 | } | ||
75 | if (ret) { | ||
76 | printk(KERN_WARNING "ARGH. About to write node to 0x%08x on flash, but there are data already there:\n", ofs); | ||
77 | printk(KERN_WARNING "0x%08x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", | ||
78 | ofs, | ||
79 | buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], | ||
80 | buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); | ||
81 | } | ||
82 | } | ||
83 | #endif | ||
84 | |||
85 | |||
86 | /* jffs2_write_dnode - given a raw_inode, allocate a full_dnode for it, | ||
87 | write it to the flash, link it into the existing inode/fragment list */ | ||
88 | |||
89 | struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const unsigned char *data, uint32_t datalen, uint32_t flash_ofs, int alloc_mode) | ||
90 | |||
91 | { | ||
92 | struct jffs2_raw_node_ref *raw; | ||
93 | struct jffs2_full_dnode *fn; | ||
94 | size_t retlen; | ||
95 | struct kvec vecs[2]; | ||
96 | int ret; | ||
97 | int retried = 0; | ||
98 | unsigned long cnt = 2; | ||
99 | |||
100 | D1(if(je32_to_cpu(ri->hdr_crc) != crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)) { | ||
101 | printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dnode()\n"); | ||
102 | BUG(); | ||
103 | } | ||
104 | ); | ||
105 | vecs[0].iov_base = ri; | ||
106 | vecs[0].iov_len = sizeof(*ri); | ||
107 | vecs[1].iov_base = (unsigned char *)data; | ||
108 | vecs[1].iov_len = datalen; | ||
109 | |||
110 | D1(writecheck(c, flash_ofs)); | ||
111 | |||
112 | if (je32_to_cpu(ri->totlen) != sizeof(*ri) + datalen) { | ||
113 | printk(KERN_WARNING "jffs2_write_dnode: ri->totlen (0x%08x) != sizeof(*ri) (0x%08zx) + datalen (0x%08x)\n", je32_to_cpu(ri->totlen), sizeof(*ri), datalen); | ||
114 | } | ||
115 | raw = jffs2_alloc_raw_node_ref(); | ||
116 | if (!raw) | ||
117 | return ERR_PTR(-ENOMEM); | ||
118 | |||
119 | fn = jffs2_alloc_full_dnode(); | ||
120 | if (!fn) { | ||
121 | jffs2_free_raw_node_ref(raw); | ||
122 | return ERR_PTR(-ENOMEM); | ||
123 | } | ||
124 | |||
125 | fn->ofs = je32_to_cpu(ri->offset); | ||
126 | fn->size = je32_to_cpu(ri->dsize); | ||
127 | fn->frags = 0; | ||
128 | |||
129 | /* check number of valid vecs */ | ||
130 | if (!datalen || !data) | ||
131 | cnt = 1; | ||
132 | retry: | ||
133 | fn->raw = raw; | ||
134 | |||
135 | raw->flash_offset = flash_ofs; | ||
136 | raw->__totlen = PAD(sizeof(*ri)+datalen); | ||
137 | raw->next_phys = NULL; | ||
138 | |||
139 | ret = jffs2_flash_writev(c, vecs, cnt, flash_ofs, &retlen, | ||
140 | (alloc_mode==ALLOC_GC)?0:f->inocache->ino); | ||
141 | |||
142 | if (ret || (retlen != sizeof(*ri) + datalen)) { | ||
143 | printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", | ||
144 | sizeof(*ri)+datalen, flash_ofs, ret, retlen); | ||
145 | |||
146 | /* Mark the space as dirtied */ | ||
147 | if (retlen) { | ||
148 | /* Doesn't belong to any inode */ | ||
149 | raw->next_in_ino = NULL; | ||
150 | |||
151 | /* Don't change raw->size to match retlen. We may have | ||
152 | written the node header already, and only the data will | ||
153 | seem corrupted, in which case the scan would skip over | ||
154 | any node we write before the original intended end of | ||
155 | this node */ | ||
156 | raw->flash_offset |= REF_OBSOLETE; | ||
157 | jffs2_add_physical_node_ref(c, raw); | ||
158 | jffs2_mark_node_obsolete(c, raw); | ||
159 | } else { | ||
160 | printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset); | ||
161 | jffs2_free_raw_node_ref(raw); | ||
162 | } | ||
163 | if (!retried && alloc_mode != ALLOC_NORETRY && (raw = jffs2_alloc_raw_node_ref())) { | ||
164 | /* Try to reallocate space and retry */ | ||
165 | uint32_t dummy; | ||
166 | struct jffs2_eraseblock *jeb = &c->blocks[flash_ofs / c->sector_size]; | ||
167 | |||
168 | retried = 1; | ||
169 | |||
170 | D1(printk(KERN_DEBUG "Retrying failed write.\n")); | ||
171 | |||
172 | ACCT_SANITY_CHECK(c,jeb); | ||
173 | D1(ACCT_PARANOIA_CHECK(jeb)); | ||
174 | |||
175 | if (alloc_mode == ALLOC_GC) { | ||
176 | ret = jffs2_reserve_space_gc(c, sizeof(*ri) + datalen, &flash_ofs, &dummy); | ||
177 | } else { | ||
178 | /* Locking pain */ | ||
179 | up(&f->sem); | ||
180 | jffs2_complete_reservation(c); | ||
181 | |||
182 | ret = jffs2_reserve_space(c, sizeof(*ri) + datalen, &flash_ofs, &dummy, alloc_mode); | ||
183 | down(&f->sem); | ||
184 | } | ||
185 | |||
186 | if (!ret) { | ||
187 | D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", flash_ofs)); | ||
188 | |||
189 | ACCT_SANITY_CHECK(c,jeb); | ||
190 | D1(ACCT_PARANOIA_CHECK(jeb)); | ||
191 | |||
192 | goto retry; | ||
193 | } | ||
194 | D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret)); | ||
195 | jffs2_free_raw_node_ref(raw); | ||
196 | } | ||
197 | /* Release the full_dnode which is now useless, and return */ | ||
198 | jffs2_free_full_dnode(fn); | ||
199 | return ERR_PTR(ret?ret:-EIO); | ||
200 | } | ||
201 | /* Mark the space used */ | ||
202 | /* If node covers at least a whole page, or if it starts at the | ||
203 | beginning of a page and runs to the end of the file, or if | ||
204 | it's a hole node, mark it REF_PRISTINE, else REF_NORMAL. | ||
205 | */ | ||
206 | if ((je32_to_cpu(ri->dsize) >= PAGE_CACHE_SIZE) || | ||
207 | ( ((je32_to_cpu(ri->offset)&(PAGE_CACHE_SIZE-1))==0) && | ||
208 | (je32_to_cpu(ri->dsize)+je32_to_cpu(ri->offset) == je32_to_cpu(ri->isize)))) { | ||
209 | raw->flash_offset |= REF_PRISTINE; | ||
210 | } else { | ||
211 | raw->flash_offset |= REF_NORMAL; | ||
212 | } | ||
213 | jffs2_add_physical_node_ref(c, raw); | ||
214 | |||
215 | /* Link into per-inode list */ | ||
216 | spin_lock(&c->erase_completion_lock); | ||
217 | raw->next_in_ino = f->inocache->nodes; | ||
218 | f->inocache->nodes = raw; | ||
219 | spin_unlock(&c->erase_completion_lock); | ||
220 | |||
221 | D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x(%d) with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n", | ||
222 | flash_ofs, ref_flags(raw), je32_to_cpu(ri->dsize), | ||
223 | je32_to_cpu(ri->csize), je32_to_cpu(ri->node_crc), | ||
224 | je32_to_cpu(ri->data_crc), je32_to_cpu(ri->totlen))); | ||
225 | |||
226 | if (retried) { | ||
227 | ACCT_SANITY_CHECK(c,NULL); | ||
228 | } | ||
229 | |||
230 | return fn; | ||
231 | } | ||
232 | |||
233 | struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_dirent *rd, const unsigned char *name, uint32_t namelen, uint32_t flash_ofs, int alloc_mode) | ||
234 | { | ||
235 | struct jffs2_raw_node_ref *raw; | ||
236 | struct jffs2_full_dirent *fd; | ||
237 | size_t retlen; | ||
238 | struct kvec vecs[2]; | ||
239 | int retried = 0; | ||
240 | int ret; | ||
241 | |||
242 | D1(printk(KERN_DEBUG "jffs2_write_dirent(ino #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x)\n", | ||
243 | je32_to_cpu(rd->pino), name, name, je32_to_cpu(rd->ino), | ||
244 | je32_to_cpu(rd->name_crc))); | ||
245 | D1(writecheck(c, flash_ofs)); | ||
246 | |||
247 | D1(if(je32_to_cpu(rd->hdr_crc) != crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)) { | ||
248 | printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dirent()\n"); | ||
249 | BUG(); | ||
250 | } | ||
251 | ); | ||
252 | |||
253 | vecs[0].iov_base = rd; | ||
254 | vecs[0].iov_len = sizeof(*rd); | ||
255 | vecs[1].iov_base = (unsigned char *)name; | ||
256 | vecs[1].iov_len = namelen; | ||
257 | |||
258 | raw = jffs2_alloc_raw_node_ref(); | ||
259 | |||
260 | if (!raw) | ||
261 | return ERR_PTR(-ENOMEM); | ||
262 | |||
263 | fd = jffs2_alloc_full_dirent(namelen+1); | ||
264 | if (!fd) { | ||
265 | jffs2_free_raw_node_ref(raw); | ||
266 | return ERR_PTR(-ENOMEM); | ||
267 | } | ||
268 | |||
269 | fd->version = je32_to_cpu(rd->version); | ||
270 | fd->ino = je32_to_cpu(rd->ino); | ||
271 | fd->nhash = full_name_hash(name, strlen(name)); | ||
272 | fd->type = rd->type; | ||
273 | memcpy(fd->name, name, namelen); | ||
274 | fd->name[namelen]=0; | ||
275 | |||
276 | retry: | ||
277 | fd->raw = raw; | ||
278 | |||
279 | raw->flash_offset = flash_ofs; | ||
280 | raw->__totlen = PAD(sizeof(*rd)+namelen); | ||
281 | raw->next_phys = NULL; | ||
282 | |||
283 | ret = jffs2_flash_writev(c, vecs, 2, flash_ofs, &retlen, | ||
284 | (alloc_mode==ALLOC_GC)?0:je32_to_cpu(rd->pino)); | ||
285 | if (ret || (retlen != sizeof(*rd) + namelen)) { | ||
286 | printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", | ||
287 | sizeof(*rd)+namelen, flash_ofs, ret, retlen); | ||
288 | /* Mark the space as dirtied */ | ||
289 | if (retlen) { | ||
290 | raw->next_in_ino = NULL; | ||
291 | raw->flash_offset |= REF_OBSOLETE; | ||
292 | jffs2_add_physical_node_ref(c, raw); | ||
293 | jffs2_mark_node_obsolete(c, raw); | ||
294 | } else { | ||
295 | printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset); | ||
296 | jffs2_free_raw_node_ref(raw); | ||
297 | } | ||
298 | if (!retried && (raw = jffs2_alloc_raw_node_ref())) { | ||
299 | /* Try to reallocate space and retry */ | ||
300 | uint32_t dummy; | ||
301 | struct jffs2_eraseblock *jeb = &c->blocks[flash_ofs / c->sector_size]; | ||
302 | |||
303 | retried = 1; | ||
304 | |||
305 | D1(printk(KERN_DEBUG "Retrying failed write.\n")); | ||
306 | |||
307 | ACCT_SANITY_CHECK(c,jeb); | ||
308 | D1(ACCT_PARANOIA_CHECK(jeb)); | ||
309 | |||
310 | if (alloc_mode == ALLOC_GC) { | ||
311 | ret = jffs2_reserve_space_gc(c, sizeof(*rd) + namelen, &flash_ofs, &dummy); | ||
312 | } else { | ||
313 | /* Locking pain */ | ||
314 | up(&f->sem); | ||
315 | jffs2_complete_reservation(c); | ||
316 | |||
317 | ret = jffs2_reserve_space(c, sizeof(*rd) + namelen, &flash_ofs, &dummy, alloc_mode); | ||
318 | down(&f->sem); | ||
319 | } | ||
320 | |||
321 | if (!ret) { | ||
322 | D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", flash_ofs)); | ||
323 | ACCT_SANITY_CHECK(c,jeb); | ||
324 | D1(ACCT_PARANOIA_CHECK(jeb)); | ||
325 | goto retry; | ||
326 | } | ||
327 | D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret)); | ||
328 | jffs2_free_raw_node_ref(raw); | ||
329 | } | ||
330 | /* Release the full_dnode which is now useless, and return */ | ||
331 | jffs2_free_full_dirent(fd); | ||
332 | return ERR_PTR(ret?ret:-EIO); | ||
333 | } | ||
334 | /* Mark the space used */ | ||
335 | raw->flash_offset |= REF_PRISTINE; | ||
336 | jffs2_add_physical_node_ref(c, raw); | ||
337 | |||
338 | spin_lock(&c->erase_completion_lock); | ||
339 | raw->next_in_ino = f->inocache->nodes; | ||
340 | f->inocache->nodes = raw; | ||
341 | spin_unlock(&c->erase_completion_lock); | ||
342 | |||
343 | if (retried) { | ||
344 | ACCT_SANITY_CHECK(c,NULL); | ||
345 | } | ||
346 | |||
347 | return fd; | ||
348 | } | ||
349 | |||
350 | /* The OS-specific code fills in the metadata in the jffs2_raw_inode for us, so that | ||
351 | we don't have to go digging in struct inode or its equivalent. It should set: | ||
352 | mode, uid, gid, (starting)isize, atime, ctime, mtime */ | ||
353 | int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | ||
354 | struct jffs2_raw_inode *ri, unsigned char *buf, | ||
355 | uint32_t offset, uint32_t writelen, uint32_t *retlen) | ||
356 | { | ||
357 | int ret = 0; | ||
358 | uint32_t writtenlen = 0; | ||
359 | |||
360 | D1(printk(KERN_DEBUG "jffs2_write_inode_range(): Ino #%u, ofs 0x%x, len 0x%x\n", | ||
361 | f->inocache->ino, offset, writelen)); | ||
362 | |||
363 | while(writelen) { | ||
364 | struct jffs2_full_dnode *fn; | ||
365 | unsigned char *comprbuf = NULL; | ||
366 | uint16_t comprtype = JFFS2_COMPR_NONE; | ||
367 | uint32_t phys_ofs, alloclen; | ||
368 | uint32_t datalen, cdatalen; | ||
369 | int retried = 0; | ||
370 | |||
371 | retry: | ||
372 | D2(printk(KERN_DEBUG "jffs2_commit_write() loop: 0x%x to write to 0x%x\n", writelen, offset)); | ||
373 | |||
374 | ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen, ALLOC_NORMAL); | ||
375 | if (ret) { | ||
376 | D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret)); | ||
377 | break; | ||
378 | } | ||
379 | down(&f->sem); | ||
380 | datalen = min_t(uint32_t, writelen, PAGE_CACHE_SIZE - (offset & (PAGE_CACHE_SIZE-1))); | ||
381 | cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), datalen); | ||
382 | |||
383 | comprtype = jffs2_compress(c, f, buf, &comprbuf, &datalen, &cdatalen); | ||
384 | |||
385 | ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | ||
386 | ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); | ||
387 | ri->totlen = cpu_to_je32(sizeof(*ri) + cdatalen); | ||
388 | ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); | ||
389 | |||
390 | ri->ino = cpu_to_je32(f->inocache->ino); | ||
391 | ri->version = cpu_to_je32(++f->highest_version); | ||
392 | ri->isize = cpu_to_je32(max(je32_to_cpu(ri->isize), offset + datalen)); | ||
393 | ri->offset = cpu_to_je32(offset); | ||
394 | ri->csize = cpu_to_je32(cdatalen); | ||
395 | ri->dsize = cpu_to_je32(datalen); | ||
396 | ri->compr = comprtype & 0xff; | ||
397 | ri->usercompr = (comprtype >> 8 ) & 0xff; | ||
398 | ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); | ||
399 | ri->data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen)); | ||
400 | |||
401 | fn = jffs2_write_dnode(c, f, ri, comprbuf, cdatalen, phys_ofs, ALLOC_NORETRY); | ||
402 | |||
403 | jffs2_free_comprbuf(comprbuf, buf); | ||
404 | |||
405 | if (IS_ERR(fn)) { | ||
406 | ret = PTR_ERR(fn); | ||
407 | up(&f->sem); | ||
408 | jffs2_complete_reservation(c); | ||
409 | if (!retried) { | ||
410 | /* Write error to be retried */ | ||
411 | retried = 1; | ||
412 | D1(printk(KERN_DEBUG "Retrying node write in jffs2_write_inode_range()\n")); | ||
413 | goto retry; | ||
414 | } | ||
415 | break; | ||
416 | } | ||
417 | ret = jffs2_add_full_dnode_to_inode(c, f, fn); | ||
418 | if (f->metadata) { | ||
419 | jffs2_mark_node_obsolete(c, f->metadata->raw); | ||
420 | jffs2_free_full_dnode(f->metadata); | ||
421 | f->metadata = NULL; | ||
422 | } | ||
423 | if (ret) { | ||
424 | /* Eep */ | ||
425 | D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in commit_write, returned %d\n", ret)); | ||
426 | jffs2_mark_node_obsolete(c, fn->raw); | ||
427 | jffs2_free_full_dnode(fn); | ||
428 | |||
429 | up(&f->sem); | ||
430 | jffs2_complete_reservation(c); | ||
431 | break; | ||
432 | } | ||
433 | up(&f->sem); | ||
434 | jffs2_complete_reservation(c); | ||
435 | if (!datalen) { | ||
436 | printk(KERN_WARNING "Eep. We didn't actually write any data in jffs2_write_inode_range()\n"); | ||
437 | ret = -EIO; | ||
438 | break; | ||
439 | } | ||
440 | D1(printk(KERN_DEBUG "increasing writtenlen by %d\n", datalen)); | ||
441 | writtenlen += datalen; | ||
442 | offset += datalen; | ||
443 | writelen -= datalen; | ||
444 | buf += datalen; | ||
445 | } | ||
446 | *retlen = writtenlen; | ||
447 | return ret; | ||
448 | } | ||
449 | |||
450 | int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const char *name, int namelen) | ||
451 | { | ||
452 | struct jffs2_raw_dirent *rd; | ||
453 | struct jffs2_full_dnode *fn; | ||
454 | struct jffs2_full_dirent *fd; | ||
455 | uint32_t alloclen, phys_ofs; | ||
456 | int ret; | ||
457 | |||
458 | /* Try to reserve enough space for both node and dirent. | ||
459 | * Just the node will do for now, though | ||
460 | */ | ||
461 | ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL); | ||
462 | D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen)); | ||
463 | if (ret) { | ||
464 | up(&f->sem); | ||
465 | return ret; | ||
466 | } | ||
467 | |||
468 | ri->data_crc = cpu_to_je32(0); | ||
469 | ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); | ||
470 | |||
471 | fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL); | ||
472 | |||
473 | D1(printk(KERN_DEBUG "jffs2_do_create created file with mode 0x%x\n", | ||
474 | jemode_to_cpu(ri->mode))); | ||
475 | |||
476 | if (IS_ERR(fn)) { | ||
477 | D1(printk(KERN_DEBUG "jffs2_write_dnode() failed\n")); | ||
478 | /* Eeek. Wave bye bye */ | ||
479 | up(&f->sem); | ||
480 | jffs2_complete_reservation(c); | ||
481 | return PTR_ERR(fn); | ||
482 | } | ||
483 | /* No data here. Only a metadata node, which will be | ||
484 | obsoleted by the first data write | ||
485 | */ | ||
486 | f->metadata = fn; | ||
487 | |||
488 | up(&f->sem); | ||
489 | jffs2_complete_reservation(c); | ||
490 | ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); | ||
491 | |||
492 | if (ret) { | ||
493 | /* Eep. */ | ||
494 | D1(printk(KERN_DEBUG "jffs2_reserve_space() for dirent failed\n")); | ||
495 | return ret; | ||
496 | } | ||
497 | |||
498 | rd = jffs2_alloc_raw_dirent(); | ||
499 | if (!rd) { | ||
500 | /* Argh. Now we treat it like a normal delete */ | ||
501 | jffs2_complete_reservation(c); | ||
502 | return -ENOMEM; | ||
503 | } | ||
504 | |||
505 | down(&dir_f->sem); | ||
506 | |||
507 | rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | ||
508 | rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); | ||
509 | rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); | ||
510 | rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); | ||
511 | |||
512 | rd->pino = cpu_to_je32(dir_f->inocache->ino); | ||
513 | rd->version = cpu_to_je32(++dir_f->highest_version); | ||
514 | rd->ino = ri->ino; | ||
515 | rd->mctime = ri->ctime; | ||
516 | rd->nsize = namelen; | ||
517 | rd->type = DT_REG; | ||
518 | rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); | ||
519 | rd->name_crc = cpu_to_je32(crc32(0, name, namelen)); | ||
520 | |||
521 | fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_NORMAL); | ||
522 | |||
523 | jffs2_free_raw_dirent(rd); | ||
524 | |||
525 | if (IS_ERR(fd)) { | ||
526 | /* dirent failed to write. Delete the inode normally | ||
527 | as if it were the final unlink() */ | ||
528 | jffs2_complete_reservation(c); | ||
529 | up(&dir_f->sem); | ||
530 | return PTR_ERR(fd); | ||
531 | } | ||
532 | |||
533 | /* Link the fd into the inode's list, obsoleting an old | ||
534 | one if necessary. */ | ||
535 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); | ||
536 | |||
537 | jffs2_complete_reservation(c); | ||
538 | up(&dir_f->sem); | ||
539 | |||
540 | return 0; | ||
541 | } | ||
542 | |||
543 | |||
544 | int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, | ||
545 | const char *name, int namelen, struct jffs2_inode_info *dead_f) | ||
546 | { | ||
547 | struct jffs2_raw_dirent *rd; | ||
548 | struct jffs2_full_dirent *fd; | ||
549 | uint32_t alloclen, phys_ofs; | ||
550 | int ret; | ||
551 | |||
552 | if (1 /* alternative branch needs testing */ || | ||
553 | !jffs2_can_mark_obsolete(c)) { | ||
554 | /* We can't mark stuff obsolete on the medium. We need to write a deletion dirent */ | ||
555 | |||
556 | rd = jffs2_alloc_raw_dirent(); | ||
557 | if (!rd) | ||
558 | return -ENOMEM; | ||
559 | |||
560 | ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_DELETION); | ||
561 | if (ret) { | ||
562 | jffs2_free_raw_dirent(rd); | ||
563 | return ret; | ||
564 | } | ||
565 | |||
566 | down(&dir_f->sem); | ||
567 | |||
568 | /* Build a deletion node */ | ||
569 | rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | ||
570 | rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); | ||
571 | rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); | ||
572 | rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); | ||
573 | |||
574 | rd->pino = cpu_to_je32(dir_f->inocache->ino); | ||
575 | rd->version = cpu_to_je32(++dir_f->highest_version); | ||
576 | rd->ino = cpu_to_je32(0); | ||
577 | rd->mctime = cpu_to_je32(get_seconds()); | ||
578 | rd->nsize = namelen; | ||
579 | rd->type = DT_UNKNOWN; | ||
580 | rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); | ||
581 | rd->name_crc = cpu_to_je32(crc32(0, name, namelen)); | ||
582 | |||
583 | fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_DELETION); | ||
584 | |||
585 | jffs2_free_raw_dirent(rd); | ||
586 | |||
587 | if (IS_ERR(fd)) { | ||
588 | jffs2_complete_reservation(c); | ||
589 | up(&dir_f->sem); | ||
590 | return PTR_ERR(fd); | ||
591 | } | ||
592 | |||
593 | /* File it. This will mark the old one obsolete. */ | ||
594 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); | ||
595 | up(&dir_f->sem); | ||
596 | } else { | ||
597 | struct jffs2_full_dirent **prev = &dir_f->dents; | ||
598 | uint32_t nhash = full_name_hash(name, namelen); | ||
599 | |||
600 | down(&dir_f->sem); | ||
601 | |||
602 | while ((*prev) && (*prev)->nhash <= nhash) { | ||
603 | if ((*prev)->nhash == nhash && | ||
604 | !memcmp((*prev)->name, name, namelen) && | ||
605 | !(*prev)->name[namelen]) { | ||
606 | struct jffs2_full_dirent *this = *prev; | ||
607 | |||
608 | D1(printk(KERN_DEBUG "Marking old dirent node (ino #%u) @%08x obsolete\n", | ||
609 | this->ino, ref_offset(this->raw))); | ||
610 | |||
611 | *prev = this->next; | ||
612 | jffs2_mark_node_obsolete(c, (this->raw)); | ||
613 | jffs2_free_full_dirent(this); | ||
614 | break; | ||
615 | } | ||
616 | prev = &((*prev)->next); | ||
617 | } | ||
618 | up(&dir_f->sem); | ||
619 | } | ||
620 | |||
621 | /* dead_f is NULL if this was a rename not a real unlink */ | ||
622 | /* Also catch the !f->inocache case, where there was a dirent | ||
623 | pointing to an inode which didn't exist. */ | ||
624 | if (dead_f && dead_f->inocache) { | ||
625 | |||
626 | down(&dead_f->sem); | ||
627 | |||
628 | while (dead_f->dents) { | ||
629 | /* There can be only deleted ones */ | ||
630 | fd = dead_f->dents; | ||
631 | |||
632 | dead_f->dents = fd->next; | ||
633 | |||
634 | if (fd->ino) { | ||
635 | printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n", | ||
636 | dead_f->inocache->ino, fd->name, fd->ino); | ||
637 | } else { | ||
638 | D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n", fd->name, dead_f->inocache->ino)); | ||
639 | } | ||
640 | jffs2_mark_node_obsolete(c, fd->raw); | ||
641 | jffs2_free_full_dirent(fd); | ||
642 | } | ||
643 | |||
644 | dead_f->inocache->nlink--; | ||
645 | /* NB: Caller must set inode nlink if appropriate */ | ||
646 | up(&dead_f->sem); | ||
647 | } | ||
648 | |||
649 | jffs2_complete_reservation(c); | ||
650 | |||
651 | return 0; | ||
652 | } | ||
653 | |||
654 | |||
655 | int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t ino, uint8_t type, const char *name, int namelen) | ||
656 | { | ||
657 | struct jffs2_raw_dirent *rd; | ||
658 | struct jffs2_full_dirent *fd; | ||
659 | uint32_t alloclen, phys_ofs; | ||
660 | int ret; | ||
661 | |||
662 | rd = jffs2_alloc_raw_dirent(); | ||
663 | if (!rd) | ||
664 | return -ENOMEM; | ||
665 | |||
666 | ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); | ||
667 | if (ret) { | ||
668 | jffs2_free_raw_dirent(rd); | ||
669 | return ret; | ||
670 | } | ||
671 | |||
672 | down(&dir_f->sem); | ||
673 | |||
674 | /* Build a deletion node */ | ||
675 | rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | ||
676 | rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); | ||
677 | rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); | ||
678 | rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); | ||
679 | |||
680 | rd->pino = cpu_to_je32(dir_f->inocache->ino); | ||
681 | rd->version = cpu_to_je32(++dir_f->highest_version); | ||
682 | rd->ino = cpu_to_je32(ino); | ||
683 | rd->mctime = cpu_to_je32(get_seconds()); | ||
684 | rd->nsize = namelen; | ||
685 | |||
686 | rd->type = type; | ||
687 | |||
688 | rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); | ||
689 | rd->name_crc = cpu_to_je32(crc32(0, name, namelen)); | ||
690 | |||
691 | fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_NORMAL); | ||
692 | |||
693 | jffs2_free_raw_dirent(rd); | ||
694 | |||
695 | if (IS_ERR(fd)) { | ||
696 | jffs2_complete_reservation(c); | ||
697 | up(&dir_f->sem); | ||
698 | return PTR_ERR(fd); | ||
699 | } | ||
700 | |||
701 | /* File it. This will mark the old one obsolete. */ | ||
702 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); | ||
703 | |||
704 | jffs2_complete_reservation(c); | ||
705 | up(&dir_f->sem); | ||
706 | |||
707 | return 0; | ||
708 | } | ||