blob: 319a70f531f8fb72c84bc110d5676e84326cfe13 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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 *
Thomas Gleixner182ec4e2005-11-07 11:16:07 +000010 * $Id: write.c,v 1.97 2005/11/07 11:14:42 gleixner Exp $
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 *
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
24int 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -070038 f->inocache->state = INO_STATE_PRESENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
Linus Torvalds1da177e2005-04-16 15:20:36 -070040 jffs2_add_ino_cache(c, f->inocache);
David Woodhouse7d200962005-04-13 14:22:38 +010041 D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino));
42 ri->ino = cpu_to_je32(f->inocache->ino);
Linus Torvalds1da177e2005-04-16 15:20:36 -070043
44 ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
45 ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
46 ri->totlen = cpu_to_je32(PAD(sizeof(*ri)));
47 ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
48 ri->mode = cpu_to_jemode(mode);
49
50 f->highest_version = 1;
51 ri->version = cpu_to_je32(f->highest_version);
52
53 return 0;
54}
55
Thomas Gleixner182ec4e2005-11-07 11:16:07 +000056/* jffs2_write_dnode - given a raw_inode, allocate a full_dnode for it,
Linus Torvalds1da177e2005-04-16 15:20:36 -070057 write it to the flash, link it into the existing inode/fragment list */
58
59struct 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)
60
61{
62 struct jffs2_raw_node_ref *raw;
63 struct jffs2_full_dnode *fn;
64 size_t retlen;
65 struct kvec vecs[2];
66 int ret;
67 int retried = 0;
68 unsigned long cnt = 2;
69
70 D1(if(je32_to_cpu(ri->hdr_crc) != crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)) {
71 printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dnode()\n");
72 BUG();
73 }
74 );
75 vecs[0].iov_base = ri;
76 vecs[0].iov_len = sizeof(*ri);
77 vecs[1].iov_base = (unsigned char *)data;
78 vecs[1].iov_len = datalen;
79
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +010080 jffs2_dbg_prewrite_paranoia_check(c, flash_ofs, vecs[0].iov_len + vecs[1].iov_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -070081
82 if (je32_to_cpu(ri->totlen) != sizeof(*ri) + datalen) {
83 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);
84 }
85 raw = jffs2_alloc_raw_node_ref();
86 if (!raw)
87 return ERR_PTR(-ENOMEM);
Thomas Gleixner182ec4e2005-11-07 11:16:07 +000088
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 fn = jffs2_alloc_full_dnode();
90 if (!fn) {
91 jffs2_free_raw_node_ref(raw);
92 return ERR_PTR(-ENOMEM);
93 }
94
95 fn->ofs = je32_to_cpu(ri->offset);
96 fn->size = je32_to_cpu(ri->dsize);
97 fn->frags = 0;
98
99 /* check number of valid vecs */
100 if (!datalen || !data)
101 cnt = 1;
102 retry:
103 fn->raw = raw;
104
105 raw->flash_offset = flash_ofs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106
Estelle Hammache9b88f472005-01-28 18:53:05 +0000107 if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(ri->version) < f->highest_version)) {
108 BUG_ON(!retried);
109 D1(printk(KERN_DEBUG "jffs2_write_dnode : dnode_version %d, "
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000110 "highest version %d -> updating dnode\n",
Estelle Hammache9b88f472005-01-28 18:53:05 +0000111 je32_to_cpu(ri->version), f->highest_version));
112 ri->version = cpu_to_je32(++f->highest_version);
113 ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
Estelle Hammachee4803c32005-01-24 21:13:42 +0000114 }
115
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 ret = jffs2_flash_writev(c, vecs, cnt, flash_ofs, &retlen,
117 (alloc_mode==ALLOC_GC)?0:f->inocache->ino);
118
119 if (ret || (retlen != sizeof(*ri) + datalen)) {
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000120 printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 sizeof(*ri)+datalen, flash_ofs, ret, retlen);
122
123 /* Mark the space as dirtied */
124 if (retlen) {
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000125 /* Don't change raw->size to match retlen. We may have
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 written the node header already, and only the data will
127 seem corrupted, in which case the scan would skip over
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000128 any node we write before the original intended end of
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 this node */
130 raw->flash_offset |= REF_OBSOLETE;
David Woodhousefcb75782006-05-22 15:23:10 +0100131 jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*ri)+datalen), NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 jffs2_mark_node_obsolete(c, raw);
133 } else {
134 printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset);
135 jffs2_free_raw_node_ref(raw);
136 }
137 if (!retried && alloc_mode != ALLOC_NORETRY && (raw = jffs2_alloc_raw_node_ref())) {
138 /* Try to reallocate space and retry */
139 uint32_t dummy;
140 struct jffs2_eraseblock *jeb = &c->blocks[flash_ofs / c->sector_size];
141
142 retried = 1;
143
144 D1(printk(KERN_DEBUG "Retrying failed write.\n"));
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000145
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100146 jffs2_dbg_acct_sanity_check(c,jeb);
147 jffs2_dbg_acct_paranoia_check(c, jeb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148
149 if (alloc_mode == ALLOC_GC) {
Ferenc Havasie631ddb2005-09-07 09:35:26 +0100150 ret = jffs2_reserve_space_gc(c, sizeof(*ri) + datalen, &flash_ofs,
151 &dummy, JFFS2_SUMMARY_INODE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 } else {
153 /* Locking pain */
154 up(&f->sem);
155 jffs2_complete_reservation(c);
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000156
Ferenc Havasie631ddb2005-09-07 09:35:26 +0100157 ret = jffs2_reserve_space(c, sizeof(*ri) + datalen, &flash_ofs,
158 &dummy, alloc_mode, JFFS2_SUMMARY_INODE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 down(&f->sem);
160 }
161
162 if (!ret) {
163 D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", flash_ofs));
164
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100165 jffs2_dbg_acct_sanity_check(c,jeb);
166 jffs2_dbg_acct_paranoia_check(c, jeb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167
168 goto retry;
169 }
170 D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret));
171 jffs2_free_raw_node_ref(raw);
172 }
173 /* Release the full_dnode which is now useless, and return */
174 jffs2_free_full_dnode(fn);
175 return ERR_PTR(ret?ret:-EIO);
176 }
177 /* Mark the space used */
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000178 /* If node covers at least a whole page, or if it starts at the
179 beginning of a page and runs to the end of the file, or if
180 it's a hole node, mark it REF_PRISTINE, else REF_NORMAL.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 */
182 if ((je32_to_cpu(ri->dsize) >= PAGE_CACHE_SIZE) ||
183 ( ((je32_to_cpu(ri->offset)&(PAGE_CACHE_SIZE-1))==0) &&
184 (je32_to_cpu(ri->dsize)+je32_to_cpu(ri->offset) == je32_to_cpu(ri->isize)))) {
185 raw->flash_offset |= REF_PRISTINE;
186 } else {
187 raw->flash_offset |= REF_NORMAL;
188 }
David Woodhousefcb75782006-05-22 15:23:10 +0100189 jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*ri)+datalen), f->inocache);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190
191 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",
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000192 flash_ofs, ref_flags(raw), je32_to_cpu(ri->dsize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 je32_to_cpu(ri->csize), je32_to_cpu(ri->node_crc),
194 je32_to_cpu(ri->data_crc), je32_to_cpu(ri->totlen)));
195
196 if (retried) {
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100197 jffs2_dbg_acct_sanity_check(c,NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 }
199
200 return fn;
201}
202
203struct 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)
204{
205 struct jffs2_raw_node_ref *raw;
206 struct jffs2_full_dirent *fd;
207 size_t retlen;
208 struct kvec vecs[2];
209 int retried = 0;
210 int ret;
211
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000212 D1(printk(KERN_DEBUG "jffs2_write_dirent(ino #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 je32_to_cpu(rd->pino), name, name, je32_to_cpu(rd->ino),
214 je32_to_cpu(rd->name_crc)));
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100215
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 D1(if(je32_to_cpu(rd->hdr_crc) != crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)) {
217 printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dirent()\n");
218 BUG();
219 }
220 );
221
222 vecs[0].iov_base = rd;
223 vecs[0].iov_len = sizeof(*rd);
224 vecs[1].iov_base = (unsigned char *)name;
225 vecs[1].iov_len = namelen;
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000226
Artem B. Bityutskiye0c8e422005-07-24 16:14:17 +0100227 jffs2_dbg_prewrite_paranoia_check(c, flash_ofs, vecs[0].iov_len + vecs[1].iov_len);
228
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 raw = jffs2_alloc_raw_node_ref();
230
231 if (!raw)
232 return ERR_PTR(-ENOMEM);
233
234 fd = jffs2_alloc_full_dirent(namelen+1);
235 if (!fd) {
236 jffs2_free_raw_node_ref(raw);
237 return ERR_PTR(-ENOMEM);
238 }
239
240 fd->version = je32_to_cpu(rd->version);
241 fd->ino = je32_to_cpu(rd->ino);
242 fd->nhash = full_name_hash(name, strlen(name));
243 fd->type = rd->type;
244 memcpy(fd->name, name, namelen);
245 fd->name[namelen]=0;
246
247 retry:
248 fd->raw = raw;
249
250 raw->flash_offset = flash_ofs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251
Estelle Hammache9b88f472005-01-28 18:53:05 +0000252 if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(rd->version) < f->highest_version)) {
253 BUG_ON(!retried);
254 D1(printk(KERN_DEBUG "jffs2_write_dirent : dirent_version %d, "
255 "highest version %d -> updating dirent\n",
256 je32_to_cpu(rd->version), f->highest_version));
257 rd->version = cpu_to_je32(++f->highest_version);
258 fd->version = je32_to_cpu(rd->version);
259 rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
Estelle Hammachee4803c32005-01-24 21:13:42 +0000260 }
261
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 ret = jffs2_flash_writev(c, vecs, 2, flash_ofs, &retlen,
263 (alloc_mode==ALLOC_GC)?0:je32_to_cpu(rd->pino));
264 if (ret || (retlen != sizeof(*rd) + namelen)) {
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000265 printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 sizeof(*rd)+namelen, flash_ofs, ret, retlen);
267 /* Mark the space as dirtied */
268 if (retlen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 raw->flash_offset |= REF_OBSOLETE;
David Woodhousefcb75782006-05-22 15:23:10 +0100270 jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*rd)+namelen), NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 jffs2_mark_node_obsolete(c, raw);
272 } else {
273 printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset);
274 jffs2_free_raw_node_ref(raw);
275 }
276 if (!retried && (raw = jffs2_alloc_raw_node_ref())) {
277 /* Try to reallocate space and retry */
278 uint32_t dummy;
279 struct jffs2_eraseblock *jeb = &c->blocks[flash_ofs / c->sector_size];
280
281 retried = 1;
282
283 D1(printk(KERN_DEBUG "Retrying failed write.\n"));
284
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100285 jffs2_dbg_acct_sanity_check(c,jeb);
286 jffs2_dbg_acct_paranoia_check(c, jeb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
288 if (alloc_mode == ALLOC_GC) {
Ferenc Havasie631ddb2005-09-07 09:35:26 +0100289 ret = jffs2_reserve_space_gc(c, sizeof(*rd) + namelen, &flash_ofs,
290 &dummy, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 } else {
292 /* Locking pain */
293 up(&f->sem);
294 jffs2_complete_reservation(c);
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000295
Ferenc Havasie631ddb2005-09-07 09:35:26 +0100296 ret = jffs2_reserve_space(c, sizeof(*rd) + namelen, &flash_ofs,
297 &dummy, alloc_mode, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 down(&f->sem);
299 }
300
301 if (!ret) {
302 D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", flash_ofs));
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100303 jffs2_dbg_acct_sanity_check(c,jeb);
304 jffs2_dbg_acct_paranoia_check(c, jeb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 goto retry;
306 }
307 D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret));
308 jffs2_free_raw_node_ref(raw);
309 }
310 /* Release the full_dnode which is now useless, and return */
311 jffs2_free_full_dirent(fd);
312 return ERR_PTR(ret?ret:-EIO);
313 }
314 /* Mark the space used */
315 raw->flash_offset |= REF_PRISTINE;
David Woodhousefcb75782006-05-22 15:23:10 +0100316 jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*rd)+namelen), f->inocache);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
318 if (retried) {
Artem B. Bityutskiy730554d2005-07-17 07:56:26 +0100319 jffs2_dbg_acct_sanity_check(c,NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 }
321
322 return fd;
323}
324
325/* The OS-specific code fills in the metadata in the jffs2_raw_inode for us, so that
326 we don't have to go digging in struct inode or its equivalent. It should set:
327 mode, uid, gid, (starting)isize, atime, ctime, mtime */
328int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000329 struct jffs2_raw_inode *ri, unsigned char *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 uint32_t offset, uint32_t writelen, uint32_t *retlen)
331{
332 int ret = 0;
333 uint32_t writtenlen = 0;
334
335 D1(printk(KERN_DEBUG "jffs2_write_inode_range(): Ino #%u, ofs 0x%x, len 0x%x\n",
336 f->inocache->ino, offset, writelen));
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000337
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 while(writelen) {
339 struct jffs2_full_dnode *fn;
340 unsigned char *comprbuf = NULL;
341 uint16_t comprtype = JFFS2_COMPR_NONE;
342 uint32_t phys_ofs, alloclen;
343 uint32_t datalen, cdatalen;
344 int retried = 0;
345
346 retry:
347 D2(printk(KERN_DEBUG "jffs2_commit_write() loop: 0x%x to write to 0x%x\n", writelen, offset));
348
Ferenc Havasie631ddb2005-09-07 09:35:26 +0100349 ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN, &phys_ofs,
350 &alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 if (ret) {
352 D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret));
353 break;
354 }
355 down(&f->sem);
356 datalen = min_t(uint32_t, writelen, PAGE_CACHE_SIZE - (offset & (PAGE_CACHE_SIZE-1)));
357 cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), datalen);
358
359 comprtype = jffs2_compress(c, f, buf, &comprbuf, &datalen, &cdatalen);
360
361 ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
362 ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
363 ri->totlen = cpu_to_je32(sizeof(*ri) + cdatalen);
364 ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
365
366 ri->ino = cpu_to_je32(f->inocache->ino);
367 ri->version = cpu_to_je32(++f->highest_version);
368 ri->isize = cpu_to_je32(max(je32_to_cpu(ri->isize), offset + datalen));
369 ri->offset = cpu_to_je32(offset);
370 ri->csize = cpu_to_je32(cdatalen);
371 ri->dsize = cpu_to_je32(datalen);
372 ri->compr = comprtype & 0xff;
373 ri->usercompr = (comprtype >> 8 ) & 0xff;
374 ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
375 ri->data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen));
376
377 fn = jffs2_write_dnode(c, f, ri, comprbuf, cdatalen, phys_ofs, ALLOC_NORETRY);
378
379 jffs2_free_comprbuf(comprbuf, buf);
380
381 if (IS_ERR(fn)) {
382 ret = PTR_ERR(fn);
383 up(&f->sem);
384 jffs2_complete_reservation(c);
385 if (!retried) {
386 /* Write error to be retried */
387 retried = 1;
388 D1(printk(KERN_DEBUG "Retrying node write in jffs2_write_inode_range()\n"));
389 goto retry;
390 }
391 break;
392 }
393 ret = jffs2_add_full_dnode_to_inode(c, f, fn);
394 if (f->metadata) {
395 jffs2_mark_node_obsolete(c, f->metadata->raw);
396 jffs2_free_full_dnode(f->metadata);
397 f->metadata = NULL;
398 }
399 if (ret) {
400 /* Eep */
401 D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in commit_write, returned %d\n", ret));
402 jffs2_mark_node_obsolete(c, fn->raw);
403 jffs2_free_full_dnode(fn);
404
405 up(&f->sem);
406 jffs2_complete_reservation(c);
407 break;
408 }
409 up(&f->sem);
410 jffs2_complete_reservation(c);
411 if (!datalen) {
412 printk(KERN_WARNING "Eep. We didn't actually write any data in jffs2_write_inode_range()\n");
413 ret = -EIO;
414 break;
415 }
416 D1(printk(KERN_DEBUG "increasing writtenlen by %d\n", datalen));
417 writtenlen += datalen;
418 offset += datalen;
419 writelen -= datalen;
420 buf += datalen;
421 }
422 *retlen = writtenlen;
423 return ret;
424}
425
426int 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)
427{
428 struct jffs2_raw_dirent *rd;
429 struct jffs2_full_dnode *fn;
430 struct jffs2_full_dirent *fd;
431 uint32_t alloclen, phys_ofs;
432 int ret;
433
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000434 /* Try to reserve enough space for both node and dirent.
435 * Just the node will do for now, though
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 */
Ferenc Havasie631ddb2005-09-07 09:35:26 +0100437 ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL,
438 JFFS2_SUMMARY_INODE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen));
440 if (ret) {
441 up(&f->sem);
442 return ret;
443 }
444
445 ri->data_crc = cpu_to_je32(0);
446 ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
447
448 fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL);
449
450 D1(printk(KERN_DEBUG "jffs2_do_create created file with mode 0x%x\n",
451 jemode_to_cpu(ri->mode)));
452
453 if (IS_ERR(fn)) {
454 D1(printk(KERN_DEBUG "jffs2_write_dnode() failed\n"));
455 /* Eeek. Wave bye bye */
456 up(&f->sem);
457 jffs2_complete_reservation(c);
458 return PTR_ERR(fn);
459 }
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000460 /* No data here. Only a metadata node, which will be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 obsoleted by the first data write
462 */
463 f->metadata = fn;
464
465 up(&f->sem);
466 jffs2_complete_reservation(c);
Ferenc Havasie631ddb2005-09-07 09:35:26 +0100467 ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
468 ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000469
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 if (ret) {
471 /* Eep. */
472 D1(printk(KERN_DEBUG "jffs2_reserve_space() for dirent failed\n"));
473 return ret;
474 }
475
476 rd = jffs2_alloc_raw_dirent();
477 if (!rd) {
478 /* Argh. Now we treat it like a normal delete */
479 jffs2_complete_reservation(c);
480 return -ENOMEM;
481 }
482
483 down(&dir_f->sem);
484
485 rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
486 rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
487 rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
488 rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
489
490 rd->pino = cpu_to_je32(dir_f->inocache->ino);
491 rd->version = cpu_to_je32(++dir_f->highest_version);
492 rd->ino = ri->ino;
493 rd->mctime = ri->ctime;
494 rd->nsize = namelen;
495 rd->type = DT_REG;
496 rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
497 rd->name_crc = cpu_to_je32(crc32(0, name, namelen));
498
499 fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_NORMAL);
500
501 jffs2_free_raw_dirent(rd);
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000502
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 if (IS_ERR(fd)) {
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000504 /* dirent failed to write. Delete the inode normally
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 as if it were the final unlink() */
506 jffs2_complete_reservation(c);
507 up(&dir_f->sem);
508 return PTR_ERR(fd);
509 }
510
511 /* Link the fd into the inode's list, obsoleting an old
512 one if necessary. */
513 jffs2_add_fd_to_list(c, fd, &dir_f->dents);
514
515 jffs2_complete_reservation(c);
516 up(&dir_f->sem);
517
518 return 0;
519}
520
521
522int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
Artem B. Bityutskiy3a69e0c2005-08-17 14:46:26 +0100523 const char *name, int namelen, struct jffs2_inode_info *dead_f,
524 uint32_t time)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525{
526 struct jffs2_raw_dirent *rd;
527 struct jffs2_full_dirent *fd;
528 uint32_t alloclen, phys_ofs;
529 int ret;
530
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000531 if (1 /* alternative branch needs testing */ ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 !jffs2_can_mark_obsolete(c)) {
533 /* We can't mark stuff obsolete on the medium. We need to write a deletion dirent */
534
535 rd = jffs2_alloc_raw_dirent();
536 if (!rd)
537 return -ENOMEM;
538
Ferenc Havasie631ddb2005-09-07 09:35:26 +0100539 ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
540 ALLOC_DELETION, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 if (ret) {
542 jffs2_free_raw_dirent(rd);
543 return ret;
544 }
545
546 down(&dir_f->sem);
547
548 /* Build a deletion node */
549 rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
550 rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
551 rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
552 rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000553
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 rd->pino = cpu_to_je32(dir_f->inocache->ino);
555 rd->version = cpu_to_je32(++dir_f->highest_version);
556 rd->ino = cpu_to_je32(0);
Artem B. Bityutskiy3a69e0c2005-08-17 14:46:26 +0100557 rd->mctime = cpu_to_je32(time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 rd->nsize = namelen;
559 rd->type = DT_UNKNOWN;
560 rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
561 rd->name_crc = cpu_to_je32(crc32(0, name, namelen));
562
563 fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_DELETION);
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000564
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 jffs2_free_raw_dirent(rd);
566
567 if (IS_ERR(fd)) {
568 jffs2_complete_reservation(c);
569 up(&dir_f->sem);
570 return PTR_ERR(fd);
571 }
572
573 /* File it. This will mark the old one obsolete. */
574 jffs2_add_fd_to_list(c, fd, &dir_f->dents);
575 up(&dir_f->sem);
576 } else {
577 struct jffs2_full_dirent **prev = &dir_f->dents;
578 uint32_t nhash = full_name_hash(name, namelen);
579
580 down(&dir_f->sem);
581
582 while ((*prev) && (*prev)->nhash <= nhash) {
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000583 if ((*prev)->nhash == nhash &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 !memcmp((*prev)->name, name, namelen) &&
585 !(*prev)->name[namelen]) {
586 struct jffs2_full_dirent *this = *prev;
587
588 D1(printk(KERN_DEBUG "Marking old dirent node (ino #%u) @%08x obsolete\n",
589 this->ino, ref_offset(this->raw)));
590
591 *prev = this->next;
592 jffs2_mark_node_obsolete(c, (this->raw));
593 jffs2_free_full_dirent(this);
594 break;
595 }
596 prev = &((*prev)->next);
597 }
598 up(&dir_f->sem);
599 }
600
601 /* dead_f is NULL if this was a rename not a real unlink */
602 /* Also catch the !f->inocache case, where there was a dirent
603 pointing to an inode which didn't exist. */
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000604 if (dead_f && dead_f->inocache) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605
606 down(&dead_f->sem);
607
Artem B. Bityuckiy32f1a952005-03-01 10:50:52 +0000608 if (S_ISDIR(OFNI_EDONI_2SFFJ(dead_f)->i_mode)) {
609 while (dead_f->dents) {
610 /* There can be only deleted ones */
611 fd = dead_f->dents;
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000612
Artem B. Bityuckiy32f1a952005-03-01 10:50:52 +0000613 dead_f->dents = fd->next;
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000614
Artem B. Bityuckiy32f1a952005-03-01 10:50:52 +0000615 if (fd->ino) {
616 printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n",
617 dead_f->inocache->ino, fd->name, fd->ino);
618 } else {
619 D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n",
620 fd->name, dead_f->inocache->ino));
621 }
622 jffs2_mark_node_obsolete(c, fd->raw);
623 jffs2_free_full_dirent(fd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 }
626
627 dead_f->inocache->nlink--;
628 /* NB: Caller must set inode nlink if appropriate */
629 up(&dead_f->sem);
630 }
631
632 jffs2_complete_reservation(c);
633
634 return 0;
635}
636
637
Artem B. Bityutskiy3a69e0c2005-08-17 14:46:26 +0100638int 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, uint32_t time)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639{
640 struct jffs2_raw_dirent *rd;
641 struct jffs2_full_dirent *fd;
642 uint32_t alloclen, phys_ofs;
643 int ret;
644
645 rd = jffs2_alloc_raw_dirent();
646 if (!rd)
647 return -ENOMEM;
648
Ferenc Havasie631ddb2005-09-07 09:35:26 +0100649 ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
650 ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 if (ret) {
652 jffs2_free_raw_dirent(rd);
653 return ret;
654 }
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000655
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 down(&dir_f->sem);
657
658 /* Build a deletion node */
659 rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
660 rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
661 rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
662 rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
663
664 rd->pino = cpu_to_je32(dir_f->inocache->ino);
665 rd->version = cpu_to_je32(++dir_f->highest_version);
666 rd->ino = cpu_to_je32(ino);
Artem B. Bityutskiy3a69e0c2005-08-17 14:46:26 +0100667 rd->mctime = cpu_to_je32(time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 rd->nsize = namelen;
669
670 rd->type = type;
671
672 rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
673 rd->name_crc = cpu_to_je32(crc32(0, name, namelen));
674
675 fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_NORMAL);
Thomas Gleixner182ec4e2005-11-07 11:16:07 +0000676
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 jffs2_free_raw_dirent(rd);
678
679 if (IS_ERR(fd)) {
680 jffs2_complete_reservation(c);
681 up(&dir_f->sem);
682 return PTR_ERR(fd);
683 }
684
685 /* File it. This will mark the old one obsolete. */
686 jffs2_add_fd_to_list(c, fd, &dir_f->dents);
687
688 jffs2_complete_reservation(c);
689 up(&dir_f->sem);
690
691 return 0;
692}