1/*
2 * JFFS2 -- Journalling Flash File System, Version 2.
3 *
4 * Copyright (C) 2001 Red Hat, Inc.
5 *
6 * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
7 *
8 * The original JFFS, from which the design for JFFS2 was derived,
9 * was designed and implemented by Axis Communications AB.
10 *
11 * The contents of this file are subject to the Red Hat eCos Public
12 * License Version 1.1 (the "Licence"); you may not use this file
13 * except in compliance with the Licence.  You may obtain a copy of
14 * the Licence at http://www.redhat.com/
15 *
16 * Software distributed under the Licence is distributed on an "AS IS"
17 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
18 * See the Licence for the specific language governing rights and
19 * limitations under the Licence.
20 *
21 * The Original Code is JFFS2 - Journalling Flash File System, version 2
22 *
23 * Alternatively, the contents of this file may be used under the
24 * terms of the GNU General Public License version 2 (the "GPL"), in
25 * which case the provisions of the GPL are applicable instead of the
26 * above.  If you wish to allow the use of your version of this file
27 * only under the terms of the GPL and not to allow others to use your
28 * version of this file under the RHEPL, indicate your decision by
29 * deleting the provisions above and replace them with the notice and
30 * other provisions required by the GPL.  If you do not delete the
31 * provisions above, a recipient may use your version of this file
32 * under either the RHEPL or the GPL.
33 *
34 * $Id: write.c,v 1.1.1.1 2008/10/15 03:27:07 james26_jang Exp $
35 *
36 */
37
38#include <linux/kernel.h>
39#include <linux/fs.h>
40#include <linux/jffs2.h>
41#include <linux/mtd/mtd.h>
42#include "nodelist.h"
43#include "crc32.h"
44
45/* jffs2_new_inode: allocate a new inode and inocache, add it to the hash,
46   fill in the raw_inode while you're at it. */
47struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri)
48{
49	struct inode *inode;
50	struct super_block *sb = dir_i->i_sb;
51	struct jffs2_inode_cache *ic;
52	struct jffs2_sb_info *c;
53	struct jffs2_inode_info *f;
54
55	D1(printk(KERN_DEBUG "jffs2_new_inode(): dir_i %ld, mode 0x%x\n", dir_i->i_ino, mode));
56
57	c = JFFS2_SB_INFO(sb);
58	memset(ri, 0, sizeof(*ri));
59
60	ic = jffs2_alloc_inode_cache();
61	if (!ic) {
62		return ERR_PTR(-ENOMEM);
63	}
64	memset(ic, 0, sizeof(*ic));
65
66	inode = new_inode(sb);
67
68	if (!inode) {
69		jffs2_free_inode_cache(ic);
70		return ERR_PTR(-ENOMEM);
71	}
72
73	/* Alloc jffs2_inode_info when that's split in 2.5 */
74
75	f = JFFS2_INODE_INFO(inode);
76	memset(f, 0, sizeof(*f));
77	init_MUTEX_LOCKED(&f->sem);
78	f->inocache = ic;
79	inode->i_nlink = f->inocache->nlink = 1;
80	f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
81	f->inocache->ino = ri->ino = inode->i_ino = ++c->highest_ino;
82	D1(printk(KERN_DEBUG "jffs2_new_inode(): Assigned ino# %d\n", ri->ino));
83	jffs2_add_ino_cache(c, f->inocache);
84
85	ri->magic = JFFS2_MAGIC_BITMASK;
86	ri->nodetype = JFFS2_NODETYPE_INODE;
87	ri->totlen = PAD(sizeof(*ri));
88	ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4);
89	ri->mode = mode;
90	f->highest_version = ri->version = 1;
91	ri->uid = current->fsuid;
92	if (dir_i->i_mode & S_ISGID) {
93		ri->gid = dir_i->i_gid;
94		if (S_ISDIR(mode))
95			ri->mode |= S_ISGID;
96	} else {
97		ri->gid = current->fsgid;
98	}
99	inode->i_mode = ri->mode;
100	inode->i_gid = ri->gid;
101	inode->i_uid = ri->uid;
102	inode->i_atime = inode->i_ctime = inode->i_mtime =
103		ri->atime = ri->mtime = ri->ctime = CURRENT_TIME;
104	inode->i_blksize = PAGE_SIZE;
105	inode->i_blocks = 0;
106	inode->i_size = 0;
107
108	insert_inode_hash(inode);
109
110	return inode;
111}
112
113/* This ought to be in core MTD code. All registered MTD devices
114   without writev should have this put in place. Bug the MTD
115   maintainer */
116static int mtd_fake_writev(struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen)
117{
118	unsigned long i;
119	size_t totlen = 0, thislen;
120	int ret = 0;
121
122	for (i=0; i<count; i++) {
123		ret = mtd->write(mtd, to, vecs[i].iov_len, &thislen, vecs[i].iov_base);
124		totlen += thislen;
125		if (ret || thislen != vecs[i].iov_len)
126			break;
127		to += vecs[i].iov_len;
128	}
129	if (retlen)
130		*retlen = totlen;
131	return ret;
132}
133
134
135static inline int mtd_writev(struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen)
136{
137	if (mtd->writev)
138		return mtd->writev(mtd,vecs,count,to,retlen);
139	else
140		return mtd_fake_writev(mtd, vecs, count, to, retlen);
141}
142
143static void writecheck(struct mtd_info *mtd, __u32 ofs)
144{
145	unsigned char buf[16];
146	ssize_t retlen;
147	int ret, i;
148
149	ret = mtd->read(mtd, ofs, 16, &retlen, buf);
150	if (ret && retlen != 16) {
151		D1(printk(KERN_DEBUG "read failed or short in writecheck(). ret %d, retlen %d\n", ret, retlen));
152		return;
153	}
154	ret = 0;
155	for (i=0; i<16; i++) {
156		if (buf[i] != 0xff)
157			ret = 1;
158	}
159	if (ret) {
160		printk(KERN_WARNING "ARGH. About to write node to 0x%08x on flash, but there's data already there:\n", ofs);
161		printk(KERN_WARNING "0x%08x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
162		       ofs,
163		       buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7],
164		       buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
165	}
166}
167
168
169
170
171/* jffs2_write_dnode - given a raw_inode, allocate a full_dnode for it,
172   write it to the flash, link it into the existing inode/fragment list */
173
174struct jffs2_full_dnode *jffs2_write_dnode(struct inode *inode, struct jffs2_raw_inode *ri, const unsigned char *data, __u32 datalen, __u32 flash_ofs,  __u32 *writelen)
175
176{
177	struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
178	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
179	struct jffs2_raw_node_ref *raw;
180	struct jffs2_full_dnode *fn;
181	ssize_t retlen;
182	struct iovec vecs[2];
183	int ret;
184
185	D1(if(ri->hdr_crc != crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)) {
186		printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dnode()\n");
187		BUG();
188	}
189	   );
190	vecs[0].iov_base = ri;
191	vecs[0].iov_len = sizeof(*ri);
192	vecs[1].iov_base = (unsigned char *)data;
193	vecs[1].iov_len = datalen;
194
195	writecheck(c->mtd, flash_ofs);
196
197	if (ri->totlen != sizeof(*ri) + datalen) {
198		printk(KERN_WARNING "jffs2_write_dnode: ri->totlen (0x%08x) != sizeof(*ri) (0x%08x) + datalen (0x%08x)\n", ri->totlen, sizeof(*ri), datalen);
199	}
200	raw = jffs2_alloc_raw_node_ref();
201	if (!raw)
202		return ERR_PTR(-ENOMEM);
203
204	fn = jffs2_alloc_full_dnode();
205	if (!fn) {
206		jffs2_free_raw_node_ref(raw);
207		return ERR_PTR(-ENOMEM);
208	}
209	raw->flash_offset = flash_ofs;
210	raw->totlen = PAD(ri->totlen);
211	raw->next_phys = NULL;
212
213	fn->ofs = ri->offset;
214	fn->size = ri->dsize;
215	fn->frags = 0;
216	fn->raw = raw;
217
218	ret = mtd_writev(c->mtd, vecs, 2, flash_ofs, &retlen);
219	if (ret || (retlen != sizeof(*ri) + datalen)) {
220		printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %d\n",
221		       sizeof(*ri)+datalen, flash_ofs, ret, retlen);
222		/* Mark the space as dirtied */
223		if (retlen) {
224			/* Doesn't belong to any inode */
225			raw->next_in_ino = NULL;
226
227			/* Don't change raw->size to match retlen. We may have
228			   written the node header already, and only the data will
229			   seem corrupted, in which case the scan would skip over
230			   any node we write before the original intended end of
231			   this node */
232			jffs2_add_physical_node_ref(c, raw, sizeof(*ri)+datalen, 1);
233			jffs2_mark_node_obsolete(c, raw);
234		} else {
235			printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset);
236			jffs2_free_raw_node_ref(raw);
237		}
238
239		/* Release the full_dnode which is now useless, and return */
240		jffs2_free_full_dnode(fn);
241		if (writelen)
242			*writelen = retlen;
243		return ERR_PTR(ret?ret:-EIO);
244	}
245	/* Mark the space used */
246	jffs2_add_physical_node_ref(c, raw, retlen, 0);
247
248	/* Link into per-inode list */
249	raw->next_in_ino = f->inocache->nodes;
250	f->inocache->nodes = raw;
251
252	D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n", flash_ofs, ri->dsize, ri->csize, ri->node_crc, ri->data_crc, ri->totlen));
253	if (writelen)
254		*writelen = retlen;
255
256	f->inocache->nodes = raw;
257	return fn;
258}
259
260struct jffs2_full_dirent *jffs2_write_dirent(struct inode *inode, struct jffs2_raw_dirent *rd, const unsigned char *name, __u32 namelen, __u32 flash_ofs,  __u32 *writelen)
261{
262	struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
263	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
264	struct jffs2_raw_node_ref *raw;
265	struct jffs2_full_dirent *fd;
266	ssize_t retlen;
267	struct iovec vecs[2];
268	int ret;
269
270	D1(printk(KERN_DEBUG "jffs2_write_dirent(ino #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x)\n", rd->pino, name, name, rd->ino, rd->name_crc));
271	writecheck(c->mtd, flash_ofs);
272
273	D1(if(rd->hdr_crc != crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)) {
274		printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dirent()\n");
275		BUG();
276	}
277	   );
278
279	vecs[0].iov_base = rd;
280	vecs[0].iov_len = sizeof(*rd);
281	vecs[1].iov_base = (unsigned char *)name;
282	vecs[1].iov_len = namelen;
283
284	raw = jffs2_alloc_raw_node_ref();
285
286	if (!raw)
287		return ERR_PTR(-ENOMEM);
288
289	fd = jffs2_alloc_full_dirent(namelen+1);
290	if (!fd) {
291		jffs2_free_raw_node_ref(raw);
292		return ERR_PTR(-ENOMEM);
293	}
294	raw->flash_offset = flash_ofs;
295	raw->totlen = PAD(rd->totlen);
296	raw->next_in_ino = f->inocache->nodes;
297	f->inocache->nodes = raw;
298	raw->next_phys = NULL;
299
300	fd->version = rd->version;
301	fd->ino = rd->ino;
302	fd->nhash = full_name_hash(name, strlen(name));
303	fd->type = rd->type;
304	memcpy(fd->name, name, namelen);
305	fd->name[namelen]=0;
306	fd->raw = raw;
307
308	ret = mtd_writev(c->mtd, vecs, 2, flash_ofs, &retlen);
309		if (ret || (retlen != sizeof(*rd) + namelen)) {
310			printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %d\n",
311			       sizeof(*rd)+namelen, flash_ofs, ret, retlen);
312		/* Mark the space as dirtied */
313			if (retlen) {
314				jffs2_add_physical_node_ref(c, raw, sizeof(*rd)+namelen, 1);
315				jffs2_mark_node_obsolete(c, raw);
316			} else {
317				printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset);
318				jffs2_free_raw_node_ref(raw);
319			}
320
321		/* Release the full_dnode which is now useless, and return */
322		jffs2_free_full_dirent(fd);
323		if (writelen)
324			*writelen = retlen;
325		return ERR_PTR(ret?ret:-EIO);
326	}
327	/* Mark the space used */
328	jffs2_add_physical_node_ref(c, raw, retlen, 0);
329	if (writelen)
330		*writelen = retlen;
331
332	f->inocache->nodes = raw;
333	return fd;
334}
335