write.c 21 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3
/*
 * JFFS2 -- Journalling Flash File System, Version 2.
 *
4
 * Copyright © 2001-2007 Red Hat, Inc.
Linus Torvalds's avatar
Linus Torvalds committed
5 6 7 8 9 10 11
 *
 * Created by David Woodhouse <dwmw2@infradead.org>
 *
 * For licensing information, see the file 'LICENCE' in this directory.
 *
 */

12 13
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

Linus Torvalds's avatar
Linus Torvalds committed
14 15 16 17 18 19 20 21 22
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/crc32.h>
#include <linux/pagemap.h>
#include <linux/mtd/mtd.h>
#include "nodelist.h"
#include "compr.h"


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)
Linus Torvalds's avatar
Linus Torvalds committed
25 26 27 28 29 30 31 32 33 34 35
{
	struct jffs2_inode_cache *ic;

	ic = jffs2_alloc_inode_cache();
	if (!ic) {
		return -ENOMEM;
	}

	memset(ic, 0, sizeof(*ic));

	f->inocache = ic;
36
	f->inocache->pino_nlink = 1; /* Will be overwritten shortly for directories */
Linus Torvalds's avatar
Linus Torvalds committed
37 38 39 40
	f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
	f->inocache->state = INO_STATE_PRESENT;

	jffs2_add_ino_cache(c, f->inocache);
41
	jffs2_dbg(1, "%s(): Assigned ino# %d\n", __func__, f->inocache->ino);
42
	ri->ino = cpu_to_je32(f->inocache->ino);
Linus Torvalds's avatar
Linus Torvalds committed
43 44 45 46 47 48 49 50 51 52 53 54 55

	ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
	ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
	ri->totlen = cpu_to_je32(PAD(sizeof(*ri)));
	ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
	ri->mode = cpu_to_jemode(mode);

	f->highest_version = 1;
	ri->version = cpu_to_je32(f->highest_version);

	return 0;
}

56
/* jffs2_write_dnode - given a raw_inode, allocate a full_dnode for it,
Linus Torvalds's avatar
Linus Torvalds committed
57 58
   write it to the flash, link it into the existing inode/fragment list */

59 60 61
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, int alloc_mode)
Linus Torvalds's avatar
Linus Torvalds committed
62 63 64 65

{
	struct jffs2_full_dnode *fn;
	size_t retlen;
66
	uint32_t flash_ofs;
Linus Torvalds's avatar
Linus Torvalds committed
67 68 69 70 71 72
	struct kvec vecs[2];
	int ret;
	int retried = 0;
	unsigned long cnt = 2;

	D1(if(je32_to_cpu(ri->hdr_crc) != crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)) {
73
		pr_crit("Eep. CRC not correct in jffs2_write_dnode()\n");
Linus Torvalds's avatar
Linus Torvalds committed
74 75 76 77 78 79 80 81 82
		BUG();
	}
	   );
	vecs[0].iov_base = ri;
	vecs[0].iov_len = sizeof(*ri);
	vecs[1].iov_base = (unsigned char *)data;
	vecs[1].iov_len = datalen;

	if (je32_to_cpu(ri->totlen) != sizeof(*ri) + datalen) {
83 84 85
		pr_warn("%s(): ri->totlen (0x%08x) != sizeof(*ri) (0x%08zx) + datalen (0x%08x)\n",
			__func__, je32_to_cpu(ri->totlen),
			sizeof(*ri), datalen);
Linus Torvalds's avatar
Linus Torvalds committed
86
	}
87

Linus Torvalds's avatar
Linus Torvalds committed
88
	fn = jffs2_alloc_full_dnode();
89
	if (!fn)
Linus Torvalds's avatar
Linus Torvalds committed
90 91 92 93 94 95
		return ERR_PTR(-ENOMEM);

	/* check number of valid vecs */
	if (!datalen || !data)
		cnt = 1;
 retry:
96
	flash_ofs = write_ofs(c);
97 98

	jffs2_dbg_prewrite_paranoia_check(c, flash_ofs, vecs[0].iov_len + vecs[1].iov_len);
Linus Torvalds's avatar
Linus Torvalds committed
99

100 101
	if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(ri->version) < f->highest_version)) {
		BUG_ON(!retried);
102 103 104
		jffs2_dbg(1, "%s(): dnode_version %d, highest version %d -> updating dnode\n",
			  __func__,
			  je32_to_cpu(ri->version), f->highest_version);
105 106
		ri->version = cpu_to_je32(++f->highest_version);
		ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
107 108
	}

Linus Torvalds's avatar
Linus Torvalds committed
109 110 111 112
	ret = jffs2_flash_writev(c, vecs, cnt, flash_ofs, &retlen,
				 (alloc_mode==ALLOC_GC)?0:f->inocache->ino);

	if (ret || (retlen != sizeof(*ri) + datalen)) {
113 114
		pr_notice("Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n",
			  sizeof(*ri) + datalen, flash_ofs, ret, retlen);
Linus Torvalds's avatar
Linus Torvalds committed
115 116 117

		/* Mark the space as dirtied */
		if (retlen) {
118
			/* Don't change raw->size to match retlen. We may have
Linus Torvalds's avatar
Linus Torvalds committed
119 120
			   written the node header already, and only the data will
			   seem corrupted, in which case the scan would skip over
121
			   any node we write before the original intended end of
Linus Torvalds's avatar
Linus Torvalds committed
122
			   this node */
123
			jffs2_add_physical_node_ref(c, flash_ofs | REF_OBSOLETE, PAD(sizeof(*ri)+datalen), NULL);
Linus Torvalds's avatar
Linus Torvalds committed
124
		} else {
125 126
			pr_notice("Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n",
				  flash_ofs);
Linus Torvalds's avatar
Linus Torvalds committed
127
		}
128
		if (!retried && alloc_mode != ALLOC_NORETRY) {
Linus Torvalds's avatar
Linus Torvalds committed
129 130 131 132 133 134
			/* Try to reallocate space and retry */
			uint32_t dummy;
			struct jffs2_eraseblock *jeb = &c->blocks[flash_ofs / c->sector_size];

			retried = 1;

135
			jffs2_dbg(1, "Retrying failed write.\n");
136

137 138
			jffs2_dbg_acct_sanity_check(c,jeb);
			jffs2_dbg_acct_paranoia_check(c, jeb);
Linus Torvalds's avatar
Linus Torvalds committed
139 140

			if (alloc_mode == ALLOC_GC) {
141 142
				ret = jffs2_reserve_space_gc(c, sizeof(*ri) + datalen, &dummy,
							     JFFS2_SUMMARY_INODE_SIZE);
Linus Torvalds's avatar
Linus Torvalds committed
143 144
			} else {
				/* Locking pain */
145
				mutex_unlock(&f->sem);
Linus Torvalds's avatar
Linus Torvalds committed
146
				jffs2_complete_reservation(c);
147

148 149
				ret = jffs2_reserve_space(c, sizeof(*ri) + datalen, &dummy,
							  alloc_mode, JFFS2_SUMMARY_INODE_SIZE);
150
				mutex_lock(&f->sem);
Linus Torvalds's avatar
Linus Torvalds committed
151 152 153
			}

			if (!ret) {
154
				flash_ofs = write_ofs(c);
155 156
				jffs2_dbg(1, "Allocated space at 0x%08x to retry failed write.\n",
					  flash_ofs);
Linus Torvalds's avatar
Linus Torvalds committed
157

158 159
				jffs2_dbg_acct_sanity_check(c,jeb);
				jffs2_dbg_acct_paranoia_check(c, jeb);
Linus Torvalds's avatar
Linus Torvalds committed
160 161 162

				goto retry;
			}
163 164
			jffs2_dbg(1, "Failed to allocate space to retry failed write: %d!\n",
				  ret);
Linus Torvalds's avatar
Linus Torvalds committed
165 166 167 168 169 170
		}
		/* Release the full_dnode which is now useless, and return */
		jffs2_free_full_dnode(fn);
		return ERR_PTR(ret?ret:-EIO);
	}
	/* Mark the space used */
171 172 173
	/* If node covers at least a whole page, or if it starts at the
	   beginning of a page and runs to the end of the file, or if
	   it's a hole node, mark it REF_PRISTINE, else REF_NORMAL.
Linus Torvalds's avatar
Linus Torvalds committed
174 175 176 177
	*/
	if ((je32_to_cpu(ri->dsize) >= PAGE_CACHE_SIZE) ||
	    ( ((je32_to_cpu(ri->offset)&(PAGE_CACHE_SIZE-1))==0) &&
	      (je32_to_cpu(ri->dsize)+je32_to_cpu(ri->offset) ==  je32_to_cpu(ri->isize)))) {
178
		flash_ofs |= REF_PRISTINE;
Linus Torvalds's avatar
Linus Torvalds committed
179
	} else {
180
		flash_ofs |= REF_NORMAL;
Linus Torvalds's avatar
Linus Torvalds committed
181
	}
182
	fn->raw = jffs2_add_physical_node_ref(c, flash_ofs, PAD(sizeof(*ri)+datalen), f->inocache);
183 184 185 186
	if (IS_ERR(fn->raw)) {
		void *hold_err = fn->raw;
		/* Release the full_dnode which is now useless, and return */
		jffs2_free_full_dnode(fn);
187
		return ERR_CAST(hold_err);
188
	}
189 190 191
	fn->ofs = je32_to_cpu(ri->offset);
	fn->size = je32_to_cpu(ri->dsize);
	fn->frags = 0;
Linus Torvalds's avatar
Linus Torvalds committed
192

193
	jffs2_dbg(1, "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",
194
		  flash_ofs & ~3, flash_ofs & 3, je32_to_cpu(ri->dsize),
Linus Torvalds's avatar
Linus Torvalds committed
195
		  je32_to_cpu(ri->csize), je32_to_cpu(ri->node_crc),
196
		  je32_to_cpu(ri->data_crc), je32_to_cpu(ri->totlen));
Linus Torvalds's avatar
Linus Torvalds committed
197 198

	if (retried) {
199
		jffs2_dbg_acct_sanity_check(c,NULL);
Linus Torvalds's avatar
Linus Torvalds committed
200 201 202 203 204
	}

	return fn;
}

205 206 207
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, int alloc_mode)
Linus Torvalds's avatar
Linus Torvalds committed
208 209 210 211
{
	struct jffs2_full_dirent *fd;
	size_t retlen;
	struct kvec vecs[2];
212
	uint32_t flash_ofs;
Linus Torvalds's avatar
Linus Torvalds committed
213 214 215
	int retried = 0;
	int ret;

216 217
	jffs2_dbg(1, "%s(ino #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x)\n",
		  __func__,
Linus Torvalds's avatar
Linus Torvalds committed
218
		  je32_to_cpu(rd->pino), name, name, je32_to_cpu(rd->ino),
219
		  je32_to_cpu(rd->name_crc));
220

Linus Torvalds's avatar
Linus Torvalds committed
221
	D1(if(je32_to_cpu(rd->hdr_crc) != crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)) {
222
		pr_crit("Eep. CRC not correct in jffs2_write_dirent()\n");
Linus Torvalds's avatar
Linus Torvalds committed
223
		BUG();
224
	   });
Linus Torvalds's avatar
Linus Torvalds committed
225

226 227 228
	if (strnlen(name, namelen) != namelen) {
		/* This should never happen, but seems to have done on at least one
		   occasion: https://dev.laptop.org/ticket/4184 */
229 230 231 232
		pr_crit("Error in jffs2_write_dirent() -- name contains zero bytes!\n");
		pr_crit("Directory inode #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x\n",
			je32_to_cpu(rd->pino), name, name, je32_to_cpu(rd->ino),
			je32_to_cpu(rd->name_crc));
233 234 235 236
		WARN_ON(1);
		return ERR_PTR(-EIO);
	}

Linus Torvalds's avatar
Linus Torvalds committed
237 238 239 240
	vecs[0].iov_base = rd;
	vecs[0].iov_len = sizeof(*rd);
	vecs[1].iov_base = (unsigned char *)name;
	vecs[1].iov_len = namelen;
241

Linus Torvalds's avatar
Linus Torvalds committed
242
	fd = jffs2_alloc_full_dirent(namelen+1);
243
	if (!fd)
Linus Torvalds's avatar
Linus Torvalds committed
244 245 246 247
		return ERR_PTR(-ENOMEM);

	fd->version = je32_to_cpu(rd->version);
	fd->ino = je32_to_cpu(rd->ino);
248
	fd->nhash = full_name_hash(name, namelen);
Linus Torvalds's avatar
Linus Torvalds committed
249 250 251 252 253
	fd->type = rd->type;
	memcpy(fd->name, name, namelen);
	fd->name[namelen]=0;

 retry:
254
	flash_ofs = write_ofs(c);
Linus Torvalds's avatar
Linus Torvalds committed
255

256
	jffs2_dbg_prewrite_paranoia_check(c, flash_ofs, vecs[0].iov_len + vecs[1].iov_len);
Linus Torvalds's avatar
Linus Torvalds committed
257

258 259
	if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(rd->version) < f->highest_version)) {
		BUG_ON(!retried);
260 261 262
		jffs2_dbg(1, "%s(): dirent_version %d, highest version %d -> updating dirent\n",
			  __func__,
			  je32_to_cpu(rd->version), f->highest_version);
263 264 265
		rd->version = cpu_to_je32(++f->highest_version);
		fd->version = je32_to_cpu(rd->version);
		rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
266 267
	}

Linus Torvalds's avatar
Linus Torvalds committed
268 269 270
	ret = jffs2_flash_writev(c, vecs, 2, flash_ofs, &retlen,
				 (alloc_mode==ALLOC_GC)?0:je32_to_cpu(rd->pino));
	if (ret || (retlen != sizeof(*rd) + namelen)) {
271 272
		pr_notice("Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n",
			  sizeof(*rd) + namelen, flash_ofs, ret, retlen);
Linus Torvalds's avatar
Linus Torvalds committed
273 274
		/* Mark the space as dirtied */
		if (retlen) {
275
			jffs2_add_physical_node_ref(c, flash_ofs | REF_OBSOLETE, PAD(sizeof(*rd)+namelen), NULL);
Linus Torvalds's avatar
Linus Torvalds committed
276
		} else {
277 278
			pr_notice("Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n",
				  flash_ofs);
Linus Torvalds's avatar
Linus Torvalds committed
279
		}
280
		if (!retried) {
Linus Torvalds's avatar
Linus Torvalds committed
281 282 283 284 285 286
			/* Try to reallocate space and retry */
			uint32_t dummy;
			struct jffs2_eraseblock *jeb = &c->blocks[flash_ofs / c->sector_size];

			retried = 1;

287
			jffs2_dbg(1, "Retrying failed write.\n");
Linus Torvalds's avatar
Linus Torvalds committed
288

289 290
			jffs2_dbg_acct_sanity_check(c,jeb);
			jffs2_dbg_acct_paranoia_check(c, jeb);
Linus Torvalds's avatar
Linus Torvalds committed
291 292

			if (alloc_mode == ALLOC_GC) {
293 294
				ret = jffs2_reserve_space_gc(c, sizeof(*rd) + namelen, &dummy,
							     JFFS2_SUMMARY_DIRENT_SIZE(namelen));
Linus Torvalds's avatar
Linus Torvalds committed
295 296
			} else {
				/* Locking pain */
297
				mutex_unlock(&f->sem);
Linus Torvalds's avatar
Linus Torvalds committed
298
				jffs2_complete_reservation(c);
299

300 301
				ret = jffs2_reserve_space(c, sizeof(*rd) + namelen, &dummy,
							  alloc_mode, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
302
				mutex_lock(&f->sem);
Linus Torvalds's avatar
Linus Torvalds committed
303 304 305
			}

			if (!ret) {
306
				flash_ofs = write_ofs(c);
307 308
				jffs2_dbg(1, "Allocated space at 0x%08x to retry failed write\n",
					  flash_ofs);
309 310
				jffs2_dbg_acct_sanity_check(c,jeb);
				jffs2_dbg_acct_paranoia_check(c, jeb);
Linus Torvalds's avatar
Linus Torvalds committed
311 312
				goto retry;
			}
313 314
			jffs2_dbg(1, "Failed to allocate space to retry failed write: %d!\n",
				  ret);
Linus Torvalds's avatar
Linus Torvalds committed
315 316 317 318 319 320
		}
		/* Release the full_dnode which is now useless, and return */
		jffs2_free_full_dirent(fd);
		return ERR_PTR(ret?ret:-EIO);
	}
	/* Mark the space used */
321 322
	fd->raw = jffs2_add_physical_node_ref(c, flash_ofs | dirent_node_state(rd),
					      PAD(sizeof(*rd)+namelen), f->inocache);
323 324 325 326
	if (IS_ERR(fd->raw)) {
		void *hold_err = fd->raw;
		/* Release the full_dirent which is now useless, and return */
		jffs2_free_full_dirent(fd);
327
		return ERR_CAST(hold_err);
328
	}
Linus Torvalds's avatar
Linus Torvalds committed
329 330

	if (retried) {
331
		jffs2_dbg_acct_sanity_check(c,NULL);
Linus Torvalds's avatar
Linus Torvalds committed
332 333 334 335 336 337 338 339 340
	}

	return fd;
}

/* The OS-specific code fills in the metadata in the jffs2_raw_inode for us, so that
   we don't have to go digging in struct inode or its equivalent. It should set:
   mode, uid, gid, (starting)isize, atime, ctime, mtime */
int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
341
			    struct jffs2_raw_inode *ri, unsigned char *buf,
Linus Torvalds's avatar
Linus Torvalds committed
342 343 344 345 346
			    uint32_t offset, uint32_t writelen, uint32_t *retlen)
{
	int ret = 0;
	uint32_t writtenlen = 0;

347 348
	jffs2_dbg(1, "%s(): Ino #%u, ofs 0x%x, len 0x%x\n",
		  __func__, f->inocache->ino, offset, writelen);
349

Linus Torvalds's avatar
Linus Torvalds committed
350 351 352 353
	while(writelen) {
		struct jffs2_full_dnode *fn;
		unsigned char *comprbuf = NULL;
		uint16_t comprtype = JFFS2_COMPR_NONE;
354
		uint32_t alloclen;
Linus Torvalds's avatar
Linus Torvalds committed
355 356 357 358
		uint32_t datalen, cdatalen;
		int retried = 0;

	retry:
359 360
		jffs2_dbg(2, "jffs2_commit_write() loop: 0x%x to write to 0x%x\n",
			  writelen, offset);
Linus Torvalds's avatar
Linus Torvalds committed
361

362
		ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN,
363
					&alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
Linus Torvalds's avatar
Linus Torvalds committed
364
		if (ret) {
365
			jffs2_dbg(1, "jffs2_reserve_space returned %d\n", ret);
Linus Torvalds's avatar
Linus Torvalds committed
366 367
			break;
		}
368
		mutex_lock(&f->sem);
Linus Torvalds's avatar
Linus Torvalds committed
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
		datalen = min_t(uint32_t, writelen, PAGE_CACHE_SIZE - (offset & (PAGE_CACHE_SIZE-1)));
		cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), datalen);

		comprtype = jffs2_compress(c, f, buf, &comprbuf, &datalen, &cdatalen);

		ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
		ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
		ri->totlen = cpu_to_je32(sizeof(*ri) + cdatalen);
		ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));

		ri->ino = cpu_to_je32(f->inocache->ino);
		ri->version = cpu_to_je32(++f->highest_version);
		ri->isize = cpu_to_je32(max(je32_to_cpu(ri->isize), offset + datalen));
		ri->offset = cpu_to_je32(offset);
		ri->csize = cpu_to_je32(cdatalen);
		ri->dsize = cpu_to_je32(datalen);
		ri->compr = comprtype & 0xff;
		ri->usercompr = (comprtype >> 8 ) & 0xff;
		ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
		ri->data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen));

390
		fn = jffs2_write_dnode(c, f, ri, comprbuf, cdatalen, ALLOC_NORETRY);
Linus Torvalds's avatar
Linus Torvalds committed
391 392 393 394 395

		jffs2_free_comprbuf(comprbuf, buf);

		if (IS_ERR(fn)) {
			ret = PTR_ERR(fn);
396
			mutex_unlock(&f->sem);
Linus Torvalds's avatar
Linus Torvalds committed
397 398 399 400
			jffs2_complete_reservation(c);
			if (!retried) {
				/* Write error to be retried */
				retried = 1;
401
				jffs2_dbg(1, "Retrying node write in jffs2_write_inode_range()\n");
Linus Torvalds's avatar
Linus Torvalds committed
402 403 404 405 406 407 408 409 410 411 412 413
				goto retry;
			}
			break;
		}
		ret = jffs2_add_full_dnode_to_inode(c, f, fn);
		if (f->metadata) {
			jffs2_mark_node_obsolete(c, f->metadata->raw);
			jffs2_free_full_dnode(f->metadata);
			f->metadata = NULL;
		}
		if (ret) {
			/* Eep */
414 415
			jffs2_dbg(1, "Eep. add_full_dnode_to_inode() failed in commit_write, returned %d\n",
				  ret);
Linus Torvalds's avatar
Linus Torvalds committed
416 417 418
			jffs2_mark_node_obsolete(c, fn->raw);
			jffs2_free_full_dnode(fn);

419
			mutex_unlock(&f->sem);
Linus Torvalds's avatar
Linus Torvalds committed
420 421 422
			jffs2_complete_reservation(c);
			break;
		}
423
		mutex_unlock(&f->sem);
Linus Torvalds's avatar
Linus Torvalds committed
424 425
		jffs2_complete_reservation(c);
		if (!datalen) {
426
			pr_warn("Eep. We didn't actually write any data in jffs2_write_inode_range()\n");
Linus Torvalds's avatar
Linus Torvalds committed
427 428 429
			ret = -EIO;
			break;
		}
430
		jffs2_dbg(1, "increasing writtenlen by %d\n", datalen);
Linus Torvalds's avatar
Linus Torvalds committed
431 432 433 434 435 436 437 438 439
		writtenlen += datalen;
		offset += datalen;
		writelen -= datalen;
		buf += datalen;
	}
	*retlen = writtenlen;
	return ret;
}

440 441 442
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 struct qstr *qstr)
Linus Torvalds's avatar
Linus Torvalds committed
443 444 445 446
{
	struct jffs2_raw_dirent *rd;
	struct jffs2_full_dnode *fn;
	struct jffs2_full_dirent *fd;
447
	uint32_t alloclen;
Linus Torvalds's avatar
Linus Torvalds committed
448 449
	int ret;

450 451
	/* Try to reserve enough space for both node and dirent.
	 * Just the node will do for now, though
Linus Torvalds's avatar
Linus Torvalds committed
452
	 */
453
	ret = jffs2_reserve_space(c, sizeof(*ri), &alloclen, ALLOC_NORMAL,
454
				JFFS2_SUMMARY_INODE_SIZE);
455
	jffs2_dbg(1, "%s(): reserved 0x%x bytes\n", __func__, alloclen);
456
	if (ret)
Linus Torvalds's avatar
Linus Torvalds committed
457
		return ret;
458 459

	mutex_lock(&f->sem);
Linus Torvalds's avatar
Linus Torvalds committed
460 461 462 463

	ri->data_crc = cpu_to_je32(0);
	ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));

464
	fn = jffs2_write_dnode(c, f, ri, NULL, 0, ALLOC_NORMAL);
Linus Torvalds's avatar
Linus Torvalds committed
465

466 467
	jffs2_dbg(1, "jffs2_do_create created file with mode 0x%x\n",
		  jemode_to_cpu(ri->mode));
Linus Torvalds's avatar
Linus Torvalds committed
468 469

	if (IS_ERR(fn)) {
470
		jffs2_dbg(1, "jffs2_write_dnode() failed\n");
Linus Torvalds's avatar
Linus Torvalds committed
471
		/* Eeek. Wave bye bye */
472
		mutex_unlock(&f->sem);
Linus Torvalds's avatar
Linus Torvalds committed
473 474 475
		jffs2_complete_reservation(c);
		return PTR_ERR(fn);
	}
476
	/* No data here. Only a metadata node, which will be
Linus Torvalds's avatar
Linus Torvalds committed
477 478 479 480
	   obsoleted by the first data write
	*/
	f->metadata = fn;

481
	mutex_unlock(&f->sem);
Linus Torvalds's avatar
Linus Torvalds committed
482
	jffs2_complete_reservation(c);
483

484
	ret = jffs2_init_security(&f->vfs_inode, &dir_f->vfs_inode, qstr);
485 486 487 488 489 490
	if (ret)
		return ret;
	ret = jffs2_init_acl_post(&f->vfs_inode);
	if (ret)
		return ret;

491 492
	ret = jffs2_reserve_space(c, sizeof(*rd)+qstr->len, &alloclen,
				ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(qstr->len));
493

Linus Torvalds's avatar
Linus Torvalds committed
494 495
	if (ret) {
		/* Eep. */
496
		jffs2_dbg(1, "jffs2_reserve_space() for dirent failed\n");
Linus Torvalds's avatar
Linus Torvalds committed
497 498 499 500 501 502 503 504 505 506
		return ret;
	}

	rd = jffs2_alloc_raw_dirent();
	if (!rd) {
		/* Argh. Now we treat it like a normal delete */
		jffs2_complete_reservation(c);
		return -ENOMEM;
	}

507
	mutex_lock(&dir_f->sem);
Linus Torvalds's avatar
Linus Torvalds committed
508 509 510

	rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
	rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
511
	rd->totlen = cpu_to_je32(sizeof(*rd) + qstr->len);
Linus Torvalds's avatar
Linus Torvalds committed
512 513 514 515 516 517
	rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));

	rd->pino = cpu_to_je32(dir_f->inocache->ino);
	rd->version = cpu_to_je32(++dir_f->highest_version);
	rd->ino = ri->ino;
	rd->mctime = ri->ctime;
518
	rd->nsize = qstr->len;
Linus Torvalds's avatar
Linus Torvalds committed
519 520
	rd->type = DT_REG;
	rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
521
	rd->name_crc = cpu_to_je32(crc32(0, qstr->name, qstr->len));
Linus Torvalds's avatar
Linus Torvalds committed
522

523
	fd = jffs2_write_dirent(c, dir_f, rd, qstr->name, qstr->len, ALLOC_NORMAL);
Linus Torvalds's avatar
Linus Torvalds committed
524 525

	jffs2_free_raw_dirent(rd);
526

Linus Torvalds's avatar
Linus Torvalds committed
527
	if (IS_ERR(fd)) {
528
		/* dirent failed to write. Delete the inode normally
Linus Torvalds's avatar
Linus Torvalds committed
529 530
		   as if it were the final unlink() */
		jffs2_complete_reservation(c);
531
		mutex_unlock(&dir_f->sem);
Linus Torvalds's avatar
Linus Torvalds committed
532 533 534 535 536 537 538 539
		return PTR_ERR(fd);
	}

	/* Link the fd into the inode's list, obsoleting an old
	   one if necessary. */
	jffs2_add_fd_to_list(c, fd, &dir_f->dents);

	jffs2_complete_reservation(c);
540
	mutex_unlock(&dir_f->sem);
Linus Torvalds's avatar
Linus Torvalds committed
541 542 543 544 545 546

	return 0;
}


int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
547 548
		    const char *name, int namelen, struct jffs2_inode_info *dead_f,
		    uint32_t time)
Linus Torvalds's avatar
Linus Torvalds committed
549 550 551
{
	struct jffs2_raw_dirent *rd;
	struct jffs2_full_dirent *fd;
552
	uint32_t alloclen;
Linus Torvalds's avatar
Linus Torvalds committed
553 554
	int ret;

555
	if (!jffs2_can_mark_obsolete(c)) {
Linus Torvalds's avatar
Linus Torvalds committed
556 557 558 559 560 561
		/* We can't mark stuff obsolete on the medium. We need to write a deletion dirent */

		rd = jffs2_alloc_raw_dirent();
		if (!rd)
			return -ENOMEM;

562
		ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen,
563
					ALLOC_DELETION, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
Linus Torvalds's avatar
Linus Torvalds committed
564 565 566 567 568
		if (ret) {
			jffs2_free_raw_dirent(rd);
			return ret;
		}

569
		mutex_lock(&dir_f->sem);
Linus Torvalds's avatar
Linus Torvalds committed
570 571 572 573 574 575

		/* Build a deletion node */
		rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
		rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
		rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
		rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
576

Linus Torvalds's avatar
Linus Torvalds committed
577 578 579
		rd->pino = cpu_to_je32(dir_f->inocache->ino);
		rd->version = cpu_to_je32(++dir_f->highest_version);
		rd->ino = cpu_to_je32(0);
580
		rd->mctime = cpu_to_je32(time);
Linus Torvalds's avatar
Linus Torvalds committed
581 582 583 584 585
		rd->nsize = namelen;
		rd->type = DT_UNKNOWN;
		rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
		rd->name_crc = cpu_to_je32(crc32(0, name, namelen));

586
		fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, ALLOC_DELETION);
587

Linus Torvalds's avatar
Linus Torvalds committed
588 589 590 591
		jffs2_free_raw_dirent(rd);

		if (IS_ERR(fd)) {
			jffs2_complete_reservation(c);
592
			mutex_unlock(&dir_f->sem);
Linus Torvalds's avatar
Linus Torvalds committed
593 594 595 596 597
			return PTR_ERR(fd);
		}

		/* File it. This will mark the old one obsolete. */
		jffs2_add_fd_to_list(c, fd, &dir_f->dents);
598
		mutex_unlock(&dir_f->sem);
Linus Torvalds's avatar
Linus Torvalds committed
599 600 601
	} else {
		uint32_t nhash = full_name_hash(name, namelen);

602
		fd = dir_f->dents;
603 604
		/* We don't actually want to reserve any space, but we do
		   want to be holding the alloc_sem when we write to flash */
605 606
		mutex_lock(&c->alloc_sem);
		mutex_lock(&dir_f->sem);
Linus Torvalds's avatar
Linus Torvalds committed
607

608 609 610 611
		for (fd = dir_f->dents; fd; fd = fd->next) {
			if (fd->nhash == nhash &&
			    !memcmp(fd->name, name, namelen) &&
			    !fd->name[namelen]) {
Linus Torvalds's avatar
Linus Torvalds committed
612

613 614
				jffs2_dbg(1, "Marking old dirent node (ino #%u) @%08x obsolete\n",
					  fd->ino, ref_offset(fd->raw));
615 616 617 618 619 620 621
				jffs2_mark_node_obsolete(c, fd->raw);
				/* We don't want to remove it from the list immediately,
				   because that screws up getdents()/seek() semantics even
				   more than they're screwed already. Turn it into a
				   node-less deletion dirent instead -- a placeholder */
				fd->raw = NULL;
				fd->ino = 0;
Linus Torvalds's avatar
Linus Torvalds committed
622 623 624
				break;
			}
		}
625
		mutex_unlock(&dir_f->sem);
Linus Torvalds's avatar
Linus Torvalds committed
626 627 628 629 630
	}

	/* dead_f is NULL if this was a rename not a real unlink */
	/* Also catch the !f->inocache case, where there was a dirent
	   pointing to an inode which didn't exist. */
631
	if (dead_f && dead_f->inocache) {
Linus Torvalds's avatar
Linus Torvalds committed
632

633
		mutex_lock(&dead_f->sem);
Linus Torvalds's avatar
Linus Torvalds committed
634

635 636 637 638
		if (S_ISDIR(OFNI_EDONI_2SFFJ(dead_f)->i_mode)) {
			while (dead_f->dents) {
				/* There can be only deleted ones */
				fd = dead_f->dents;
639

640
				dead_f->dents = fd->next;
641

642
				if (fd->ino) {
643 644 645
					pr_warn("Deleting inode #%u with active dentry \"%s\"->ino #%u\n",
						dead_f->inocache->ino,
						fd->name, fd->ino);
646
				} else {
647 648 649
					jffs2_dbg(1, "Removing deletion dirent for \"%s\" from dir ino #%u\n",
						  fd->name,
						  dead_f->inocache->ino);
650
				}
651 652
				if (fd->raw)
					jffs2_mark_node_obsolete(c, fd->raw);
653
				jffs2_free_full_dirent(fd);
Linus Torvalds's avatar
Linus Torvalds committed
654
			}
655 656 657
			dead_f->inocache->pino_nlink = 0;
		} else
			dead_f->inocache->pino_nlink--;
Linus Torvalds's avatar
Linus Torvalds committed
658
		/* NB: Caller must set inode nlink if appropriate */
659
		mutex_unlock(&dead_f->sem);
Linus Torvalds's avatar
Linus Torvalds committed
660 661 662 663 664 665 666 667
	}

	jffs2_complete_reservation(c);

	return 0;
}


668
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, uint32_t time)
Linus Torvalds's avatar
Linus Torvalds committed
669 670 671
{
	struct jffs2_raw_dirent *rd;
	struct jffs2_full_dirent *fd;
672
	uint32_t alloclen;
Linus Torvalds's avatar
Linus Torvalds committed
673 674 675 676 677 678
	int ret;

	rd = jffs2_alloc_raw_dirent();
	if (!rd)
		return -ENOMEM;

679
	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen,
680
				ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
Linus Torvalds's avatar
Linus Torvalds committed
681 682 683 684
	if (ret) {
		jffs2_free_raw_dirent(rd);
		return ret;
	}
685

686
	mutex_lock(&dir_f->sem);
Linus Torvalds's avatar
Linus Torvalds committed
687 688 689 690 691 692 693 694 695 696

	/* Build a deletion node */
	rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
	rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
	rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
	rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));

	rd->pino = cpu_to_je32(dir_f->inocache->ino);
	rd->version = cpu_to_je32(++dir_f->highest_version);
	rd->ino = cpu_to_je32(ino);
697
	rd->mctime = cpu_to_je32(time);
Linus Torvalds's avatar
Linus Torvalds committed
698 699 700 701 702 703 704
	rd->nsize = namelen;

	rd->type = type;

	rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
	rd->name_crc = cpu_to_je32(crc32(0, name, namelen));

705
	fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, ALLOC_NORMAL);
706

Linus Torvalds's avatar
Linus Torvalds committed
707 708 709 710
	jffs2_free_raw_dirent(rd);

	if (IS_ERR(fd)) {
		jffs2_complete_reservation(c);
711
		mutex_unlock(&dir_f->sem);
Linus Torvalds's avatar
Linus Torvalds committed
712 713 714 715 716 717 718
		return PTR_ERR(fd);
	}

	/* File it. This will mark the old one obsolete. */
	jffs2_add_fd_to_list(c, fd, &dir_f->dents);

	jffs2_complete_reservation(c);
719
	mutex_unlock(&dir_f->sem);
Linus Torvalds's avatar
Linus Torvalds committed
720 721 722

	return 0;
}