linux-old/fs/jffs2/readinode.c
<<
>>
Prefs
   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: readinode.c,v 1.58.2.8 2003/11/02 13:54:20 dwmw2 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
  50D1(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
  67int 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
  78static 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 */
  99int 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
 225void 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
 246void 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
 462void 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
 509
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.