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

Subversion Repositories or1k

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

Go to most recent revision | 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: readinode.c,v 1.1.1.1 2004-04-15 01:11:06 phoenix Exp $
35
 *
36
 */
37
 
38
/* Given an inode, probably with existing list of fragments, add the new node
39
 * to the fragment list.
40
 */
41
#include <linux/kernel.h>
42
#include <linux/slab.h>
43
#include <linux/fs.h>
44
#include <linux/mtd/mtd.h>
45
#include <linux/jffs2.h>
46
#include "nodelist.h"
47
#include <linux/crc32.h>
48
 
49
 
50
D1(void jffs2_print_frag_list(struct jffs2_inode_info *f)
51
{
52
        struct jffs2_node_frag *this = f->fraglist;
53
 
54
        while(this) {
55
                if (this->node)
56
                        printk(KERN_DEBUG "frag %04x-%04x: 0x%08x on flash (*%p->%p)\n", this->ofs, this->ofs+this->size, this->node->raw->flash_offset &~3, this, this->next);
57
                else
58
                        printk(KERN_DEBUG "frag %04x-%04x: hole (*%p->%p)\n", this->ofs, this->ofs+this->size, this, this->next);
59
                this = this->next;
60
        }
61
        if (f->metadata) {
62
                printk(KERN_DEBUG "metadata at 0x%08x\n", f->metadata->raw->flash_offset &~3);
63
        }
64
})
65
 
66
 
67
int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn)
68
{
69
        int ret;
70
        D1(printk(KERN_DEBUG "jffs2_add_full_dnode_to_inode(ino #%u, f %p, fn %p)\n", f->inocache->ino, f, fn));
71
 
72
        ret = jffs2_add_full_dnode_to_fraglist(c, &f->fraglist, fn);
73
 
74
        D2(jffs2_print_frag_list(f));
75
        return ret;
76
}
77
 
78
static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_frag *this)
79
{
80
        if (this->node) {
81
                this->node->frags--;
82
                if (!this->node->frags) {
83
                        /* The node has no valid frags left. It's totally obsoleted */
84
                        D2(printk(KERN_DEBUG "Marking old node @0x%08x (0x%04x-0x%04x) obsolete\n",
85
                                  this->node->raw->flash_offset &~3, this->node->ofs, this->node->ofs+this->node->size));
86
                        jffs2_mark_node_obsolete(c, this->node->raw);
87
                        jffs2_free_full_dnode(this->node);
88
                } else {
89
                        D2(printk(KERN_DEBUG "Not marking old node @0x%08x (0x%04x-0x%04x) obsolete. frags is %d\n",
90
                                  this->node->raw->flash_offset &~3, this->node->ofs, this->node->ofs+this->node->size,
91
                                  this->node->frags));
92
                }
93
 
94
        }
95
        jffs2_free_node_frag(this);
96
}
97
 
98
/* Doesn't set inode->i_size */
99
int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct jffs2_node_frag **list, struct jffs2_full_dnode *fn)
100
{
101
 
102
        struct jffs2_node_frag *this, **prev, *old;
103
        struct jffs2_node_frag *newfrag, *newfrag2;
104
        __u32 lastend = 0;
105
 
106
 
107
        newfrag = jffs2_alloc_node_frag();
108
        if (!newfrag) {
109
                return -ENOMEM;
110
        }
111
 
112
        D2(if (fn->raw)
113
                printk(KERN_DEBUG "adding node %04x-%04x @0x%08x on flash, newfrag *%p\n", fn->ofs, fn->ofs+fn->size, fn->raw->flash_offset &~3, newfrag);
114
        else
115
                printk(KERN_DEBUG "adding hole node %04x-%04x on flash, newfrag *%p\n", fn->ofs, fn->ofs+fn->size, newfrag));
116
 
117
        prev = list;
118
        this = *list;
119
 
120
        if (!fn->size) {
121
                jffs2_free_node_frag(newfrag);
122
                return 0;
123
        }
124
 
125
        newfrag->ofs = fn->ofs;
126
        newfrag->size = fn->size;
127
        newfrag->node = fn;
128
        newfrag->node->frags = 1;
129
        newfrag->next = (void *)0xdeadbeef;
130
 
131
        /* Skip all the nodes which are completed before this one starts */
132
        while(this && fn->ofs >= this->ofs+this->size) {
133
                lastend = this->ofs + this->size;
134
 
135
                D2(printk(KERN_DEBUG "j_a_f_d_t_f: skipping frag 0x%04x-0x%04x; phys 0x%08x (*%p->%p)\n",
136
                          this->ofs, this->ofs+this->size, this->node?(this->node->raw->flash_offset &~3):0xffffffff, this, this->next));
137
                prev = &this->next;
138
                this = this->next;
139
        }
140
 
141
        /* See if we ran off the end of the list */
142
        if (!this) {
143
                /* We did */
144
                if (lastend < fn->ofs) {
145
                        /* ... and we need to put a hole in before the new node */
146
                        struct jffs2_node_frag *holefrag = jffs2_alloc_node_frag();
147
                        if (!holefrag)
148
                                return -ENOMEM;
149
                        holefrag->ofs = lastend;
150
                        holefrag->size = fn->ofs - lastend;
151
                        holefrag->next = NULL;
152
                        holefrag->node = NULL;
153
                        *prev = holefrag;
154
                        prev = &holefrag->next;
155
                }
156
                newfrag->next = NULL;
157
                *prev = newfrag;
158
                return 0;
159
        }
160
 
161
        D2(printk(KERN_DEBUG "j_a_f_d_t_f: dealing with frag 0x%04x-0x%04x; phys 0x%08x (*%p->%p)\n",
162
                  this->ofs, this->ofs+this->size, this->node?(this->node->raw->flash_offset &~3):0xffffffff, this, this->next));
163
 
164
        /* OK. 'this' is pointing at the first frag that fn->ofs at least partially obsoletes,
165
         * - i.e. fn->ofs < this->ofs+this->size && fn->ofs >= this->ofs
166
         */
167
        if (fn->ofs > this->ofs) {
168
                /* This node isn't completely obsoleted. The start of it remains valid */
169
                if (this->ofs + this->size > fn->ofs + fn->size) {
170
                        /* The new node splits 'this' frag into two */
171
                        newfrag2 = jffs2_alloc_node_frag();
172
                        if (!newfrag2) {
173
                                jffs2_free_node_frag(newfrag);
174
                                return -ENOMEM;
175
                        }
176
                        D1(printk(KERN_DEBUG "split old frag 0x%04x-0x%04x -->", this->ofs, this->ofs+this->size);
177
                        if (this->node)
178
                                printk("phys 0x%08x\n", this->node->raw->flash_offset &~3);
179
                        else
180
                                printk("hole\n");
181
                           )
182
                        newfrag2->ofs = fn->ofs + fn->size;
183
                        newfrag2->size = (this->ofs+this->size) - newfrag2->ofs;
184
                        newfrag2->next = this->next;
185
                        newfrag2->node = this->node;
186
                        if (this->node)
187
                                this->node->frags++;
188
                        newfrag->next = newfrag2;
189
                        this->next = newfrag;
190
                        this->size = newfrag->ofs - this->ofs;
191
                        return 0;
192
                }
193
                /* New node just reduces 'this' frag in size, doesn't split it */
194
                this->size = fn->ofs - this->ofs;
195
                newfrag->next = this->next;
196
                this->next = newfrag;
197
                this = newfrag->next;
198
        } else {
199
                D2(printk(KERN_DEBUG "Inserting newfrag (*%p) in before 'this' (*%p)\n", newfrag, this));
200
                *prev = newfrag;
201
                newfrag->next = this;
202
        }
203
        /* OK, now we have newfrag added in the correct place in the list, but
204
           newfrag->next points to a fragment which may be overlapping it
205
        */
206
        while (this && newfrag->ofs + newfrag->size >= this->ofs + this->size) {
207
                /* 'this' frag is obsoleted. */
208
                old = this;
209
                this = old->next;
210
                jffs2_obsolete_node_frag(c, old);
211
        }
212
        /* Now we're pointing at the first frag which isn't totally obsoleted by
213
           the new frag */
214
        newfrag->next = this;
215
 
216
        if (!this || newfrag->ofs + newfrag->size == this->ofs) {
217
                return 0;
218
        }
219
        /* Still some overlap */
220
        this->size = (this->ofs + this->size) - (newfrag->ofs + newfrag->size);
221
        this->ofs = newfrag->ofs + newfrag->size;
222
        return 0;
223
}
224
 
225
void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct jffs2_node_frag **list, __u32 size)
226
{
227
        D1(printk(KERN_DEBUG "Truncating fraglist to 0x%08x bytes\n", size));
228
 
229
        while (*list) {
230
                if ((*list)->ofs >= size) {
231
                        struct jffs2_node_frag *this = *list;
232
                        *list = this->next;
233
                        D1(printk(KERN_DEBUG "Removing frag 0x%08x-0x%08x\n", this->ofs, this->ofs+this->size));
234
                        jffs2_obsolete_node_frag(c, this);
235
                        continue;
236
                } else if ((*list)->ofs + (*list)->size > size) {
237
                        D1(printk(KERN_DEBUG "Truncating frag 0x%08x-0x%08x\n", (*list)->ofs, (*list)->ofs + (*list)->size));
238
                        (*list)->size = size - (*list)->ofs;
239
                }
240
                list = &(*list)->next;
241
        }
242
}
243
 
244
/* Scan the list of all nodes present for this ino, build map of versions, etc. */
245
 
246
void jffs2_read_inode (struct inode *inode)
247
{
248
        struct jffs2_tmp_dnode_info *tn_list, *tn;
249
        struct jffs2_full_dirent *fd_list;
250
        struct jffs2_inode_info *f;
251
        struct jffs2_full_dnode *fn = NULL;
252
        struct jffs2_sb_info *c;
253
        struct jffs2_raw_inode latest_node;
254
        __u32 latest_mctime, mctime_ver;
255
        __u32 mdata_ver = 0;
256
        int ret;
257
        ssize_t retlen;
258
 
259
        D1(printk(KERN_DEBUG "jffs2_read_inode(): inode->i_ino == %lu\n", inode->i_ino));
260
 
261
        f = JFFS2_INODE_INFO(inode);
262
        c = JFFS2_SB_INFO(inode->i_sb);
263
 
264
        memset(f, 0, sizeof(*f));
265
        D2(printk(KERN_DEBUG "getting inocache\n"));
266
        init_MUTEX(&f->sem);
267
        f->inocache = jffs2_get_ino_cache(c, inode->i_ino);
268
        D2(printk(KERN_DEBUG "jffs2_read_inode(): Got inocache at %p\n", f->inocache));
269
 
270
        if (!f->inocache && inode->i_ino == 1) {
271
                /* Special case - no root inode on medium */
272
                f->inocache = jffs2_alloc_inode_cache();
273
                if (!f->inocache) {
274
                        printk(KERN_CRIT "jffs2_read_inode(): Cannot allocate inocache for root inode\n");
275
                        make_bad_inode(inode);
276
                        return;
277
                }
278
                D1(printk(KERN_DEBUG "jffs2_read_inode(): Creating inocache for root inode\n"));
279
                memset(f->inocache, 0, sizeof(struct jffs2_inode_cache));
280
                f->inocache->ino = f->inocache->nlink = 1;
281
                f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
282
                jffs2_add_ino_cache(c, f->inocache);
283
        }
284
        if (!f->inocache) {
285
                printk(KERN_WARNING "jffs2_read_inode() on nonexistent ino %lu\n", (unsigned long)inode->i_ino);
286
                make_bad_inode(inode);
287
                return;
288
        }
289
        D1(printk(KERN_DEBUG "jffs2_read_inode(): ino #%lu nlink is %d\n", (unsigned long)inode->i_ino, f->inocache->nlink));
290
        inode->i_nlink = f->inocache->nlink;
291
 
292
        /* Grab all nodes relevant to this ino */
293
        ret = jffs2_get_inode_nodes(c, inode->i_ino, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver);
294
 
295
        if (ret) {
296
                printk(KERN_CRIT "jffs2_get_inode_nodes() for ino %lu returned %d\n", inode->i_ino, ret);
297
                make_bad_inode(inode);
298
                return;
299
        }
300
        f->dents = fd_list;
301
 
302
        while (tn_list) {
303
                tn = tn_list;
304
 
305
                fn = tn->fn;
306
 
307
                if (f->metadata && tn->version > mdata_ver) {
308
                        D1(printk(KERN_DEBUG "Obsoleting old metadata at 0x%08x\n", f->metadata->raw->flash_offset &~3));
309
                        jffs2_mark_node_obsolete(c, f->metadata->raw);
310
                        jffs2_free_full_dnode(f->metadata);
311
                        f->metadata = NULL;
312
 
313
                        mdata_ver = 0;
314
                }
315
 
316
                if (fn->size) {
317
                        jffs2_add_full_dnode_to_inode(c, f, fn);
318
                } else {
319
                        /* Zero-sized node at end of version list. Just a metadata update */
320
                        D1(printk(KERN_DEBUG "metadata @%08x: ver %d\n", fn->raw->flash_offset &~3, tn->version));
321
                        f->metadata = fn;
322
                        mdata_ver = tn->version;
323
                }
324
                tn_list = tn->next;
325
                jffs2_free_tmp_dnode_info(tn);
326
        }
327
        if (!fn) {
328
                /* No data nodes for this inode. */
329
                if (inode->i_ino != 1) {
330
                        printk(KERN_WARNING "jffs2_read_inode(): No data nodes found for ino #%lu\n", inode->i_ino);
331
                        if (!fd_list) {
332
                                make_bad_inode(inode);
333
                                return;
334
                        }
335
                        printk(KERN_WARNING "jffs2_read_inode(): But it has children so we fake some modes for it\n");
336
                }
337
                inode->i_mode = S_IFDIR | S_IRUGO | S_IWUSR | S_IXUGO;
338
                latest_node.version = 0;
339
                inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME;
340
                inode->i_nlink = f->inocache->nlink;
341
                inode->i_size = 0;
342
        } else {
343
                __u32 crc;
344
 
345
                ret = c->mtd->read(c->mtd, fn->raw->flash_offset & ~3, sizeof(latest_node), &retlen, (void *)&latest_node);
346
                if (ret || retlen != sizeof(latest_node)) {
347
                        printk(KERN_NOTICE "MTD read in jffs2_read_inode() failed: Returned %d, %ld of %d bytes read\n",
348
                               ret, (long)retlen, sizeof(latest_node));
349
                        jffs2_clear_inode(inode);
350
                        make_bad_inode(inode);
351
                        return;
352
                }
353
 
354
                crc = crc32(0, &latest_node, sizeof(latest_node)-8);
355
                if (crc != latest_node.node_crc) {
356
                        printk(KERN_NOTICE "CRC failed for read_inode of inode %ld at physical location 0x%x\n", inode->i_ino, fn->raw->flash_offset & ~3);
357
                        jffs2_clear_inode(inode);
358
                        make_bad_inode(inode);
359
                        return;
360
                }
361
 
362
                inode->i_mode = latest_node.mode;
363
                inode->i_uid = latest_node.uid;
364
                inode->i_gid = latest_node.gid;
365
                inode->i_size = latest_node.isize;
366
                if (S_ISREG(inode->i_mode))
367
                        jffs2_truncate_fraglist(c, &f->fraglist, latest_node.isize);
368
                inode->i_atime = latest_node.atime;
369
                inode->i_mtime = latest_node.mtime;
370
                inode->i_ctime = latest_node.ctime;
371
        }
372
 
373
        /* OK, now the special cases. Certain inode types should
374
           have only one data node, and it's kept as the metadata
375
           node */
376
        if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode) ||
377
            S_ISLNK(inode->i_mode)) {
378
                if (f->metadata) {
379
                        printk(KERN_WARNING "Argh. Special inode #%lu with mode 0%o had metadata node\n", inode->i_ino, inode->i_mode);
380
                        jffs2_clear_inode(inode);
381
                        make_bad_inode(inode);
382
                        return;
383
                }
384
                if (!f->fraglist) {
385
                        printk(KERN_WARNING "Argh. Special inode #%lu with mode 0%o has no fragments\n", inode->i_ino, inode->i_mode);
386
                        jffs2_clear_inode(inode);
387
                        make_bad_inode(inode);
388
                        return;
389
                }
390
                /* ASSERT: f->fraglist != NULL */
391
                if (f->fraglist->next) {
392
                        printk(KERN_WARNING "Argh. Special inode #%lu with mode 0%o had more than one node\n", inode->i_ino, inode->i_mode);
393
                        /* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */
394
                        jffs2_clear_inode(inode);
395
                        make_bad_inode(inode);
396
                        return;
397
                }
398
                /* OK. We're happy */
399
                f->metadata = f->fraglist->node;
400
                jffs2_free_node_frag(f->fraglist);
401
                f->fraglist = NULL;
402
        }
403
 
404
        inode->i_blksize = PAGE_SIZE;
405
        inode->i_blocks = (inode->i_size + 511) >> 9;
406
 
407
        switch (inode->i_mode & S_IFMT) {
408
                unsigned short rdev;
409
 
410
        case S_IFLNK:
411
                inode->i_op = &jffs2_symlink_inode_operations;
412
                /* Hack to work around broken isize in old symlink code.
413
                   Remove this when dwmw2 comes to his senses and stops
414
                   symlinks from being an entirely gratuitous special
415
                   case. */
416
                if (!inode->i_size)
417
                        inode->i_size = latest_node.dsize;
418
                break;
419
 
420
        case S_IFDIR:
421
                if (mctime_ver > latest_node.version) {
422
                        /* The times in the latest_node are actually older than
423
                           mctime in the latest dirent. Cheat. */
424
                        inode->i_mtime = inode->i_ctime = inode->i_atime =
425
                                latest_mctime;
426
                }
427
                inode->i_op = &jffs2_dir_inode_operations;
428
                inode->i_fop = &jffs2_dir_operations;
429
                break;
430
 
431
        case S_IFREG:
432
                inode->i_op = &jffs2_file_inode_operations;
433
                inode->i_fop = &jffs2_file_operations;
434
                inode->i_mapping->a_ops = &jffs2_file_address_operations;
435
                inode->i_mapping->nrpages = 0;
436
                break;
437
 
438
        case S_IFBLK:
439
        case S_IFCHR:
440
                /* Read the device numbers from the media */
441
                D1(printk(KERN_DEBUG "Reading device numbers from flash\n"));
442
                if (jffs2_read_dnode(c, f->metadata, (char *)&rdev, 0, sizeof(rdev)) < 0) {
443
                        /* Eep */
444
                        printk(KERN_NOTICE "Read device numbers for inode %lu failed\n", (unsigned long)inode->i_ino);
445
                        jffs2_clear_inode(inode);
446
                        make_bad_inode(inode);
447
                        return;
448
                }
449
 
450
        case S_IFSOCK:
451
        case S_IFIFO:
452
                inode->i_op = &jffs2_file_inode_operations;
453
                init_special_inode(inode, inode->i_mode, kdev_t_to_nr(MKDEV(rdev>>8, rdev&0xff)));
454
                break;
455
 
456
        default:
457
                printk(KERN_WARNING "jffs2_read_inode(): Bogus imode %o for ino %lu", inode->i_mode, (unsigned long)inode->i_ino);
458
        }
459
        D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n"));
460
}
461
 
462
void jffs2_clear_inode (struct inode *inode)
463
{
464
        /* We can forget about this inode for now - drop all
465
         *  the nodelists associated with it, etc.
466
         */
467
        struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
468
        struct jffs2_node_frag *frag, *frags;
469
        struct jffs2_full_dirent *fd, *fds;
470
        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
471
        int deleted;
472
 
473
        D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode));
474
 
475
        down(&f->sem);
476
        deleted = f->inocache && !f->inocache->nlink;
477
 
478
        frags = f->fraglist;
479
        fds = f->dents;
480
        if (f->metadata) {
481
                if (deleted)
482
                        jffs2_mark_node_obsolete(c, f->metadata->raw);
483
                jffs2_free_full_dnode(f->metadata);
484
        }
485
 
486
        while (frags) {
487
                frag = frags;
488
                frags = frag->next;
489
                D2(printk(KERN_DEBUG "jffs2_clear_inode: frag at 0x%x-0x%x: node %p, frags %d--\n", frag->ofs, frag->ofs+frag->size, frag->node, frag->node?frag->node->frags:0));
490
 
491
                if (frag->node && !(--frag->node->frags)) {
492
                        /* Not a hole, and it's the final remaining frag of this node. Free the node */
493
                        if (deleted)
494
                                jffs2_mark_node_obsolete(c, frag->node->raw);
495
 
496
                        jffs2_free_full_dnode(frag->node);
497
                }
498
                jffs2_free_node_frag(frag);
499
        }
500
        while(fds) {
501
                fd = fds;
502
                fds = fd->next;
503
                jffs2_free_full_dirent(fd);
504
        }
505
 
506
        up(&f->sem);
507
};
508
 

powered by: WebSVN 2.1.0

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