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.30.2.2 2003/11/02 13:51:18 dwmw2 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 <linux/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. */
jffs2_new_inode(struct inode * dir_i,int mode,struct jffs2_raw_inode * ri)47 struct 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 */
mtd_fake_writev(struct mtd_info * mtd,const struct iovec * vecs,unsigned long count,loff_t to,size_t * retlen)116 static 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 
mtd_writev(struct mtd_info * mtd,const struct iovec * vecs,unsigned long count,loff_t to,size_t * retlen)135 static 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 
writecheck(struct mtd_info * mtd,__u32 ofs)143 static 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 
jffs2_write_dnode(struct inode * inode,struct jffs2_raw_inode * ri,const unsigned char * data,__u32 datalen,__u32 flash_ofs,__u32 * writelen)174 struct 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 
jffs2_write_dirent(struct inode * inode,struct jffs2_raw_dirent * rd,const unsigned char * name,__u32 namelen,__u32 flash_ofs,__u32 * writelen)260 struct 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