OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [jffs2/] [write.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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 2004-04-15 01:11:09 phoenix 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. */
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 */
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
 
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
 
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
 
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
 
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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.