The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/jffs2/build.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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: build.c,v 1.16.2.3 2003/04/30 09:43:32 dwmw2 Exp $
   35  *
   36  */
   37 
   38 #include <linux/kernel.h>
   39 #include <linux/jffs2.h>
   40 #include <linux/slab.h>
   41 #include "nodelist.h"
   42 
   43 int jffs2_build_inode_pass1(struct jffs2_sb_info *, struct jffs2_inode_cache *);
   44 int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *);
   45 
   46 static inline struct jffs2_inode_cache *
   47 first_inode_chain(int *i, struct jffs2_sb_info *c)
   48 {
   49         for (; *i < INOCACHE_HASHSIZE; (*i)++) {
   50                 if (c->inocache_list[*i])
   51                         return c->inocache_list[*i];
   52         }
   53         return NULL;
   54 }
   55 
   56 static inline struct jffs2_inode_cache *
   57 next_inode(int *i, struct jffs2_inode_cache *ic, struct jffs2_sb_info *c)
   58 {
   59         /* More in this chain? */
   60         if (ic->next)
   61                 return ic->next;
   62         (*i)++;
   63         return first_inode_chain(i, c);
   64 }
   65 
   66 #define for_each_inode(i, c, ic)                        \
   67         for (i = 0, ic = first_inode_chain(&i, (c));    \
   68              ic;                                        \
   69              ic = next_inode(&i, ic, (c)))
   70 
   71 /* Scan plan:
   72  - Scan physical nodes. Build map of inodes/dirents. Allocate inocaches as we go
   73  - Scan directory tree from top down, setting nlink in inocaches
   74  - Scan inocaches for inodes with nlink==0
   75 */
   76 int jffs2_build_filesystem(struct jffs2_sb_info *c)
   77 {
   78         int ret;
   79         int i;
   80         struct jffs2_inode_cache *ic;
   81 
   82         /* First, scan the medium and build all the inode caches with
   83            lists of physical nodes */
   84 
   85         c->flags |= JFFS2_SB_FLAG_MOUNTING;
   86         ret = jffs2_scan_medium(c);
   87         c->flags &= ~JFFS2_SB_FLAG_MOUNTING;
   88 
   89         if (ret)
   90                 return ret;
   91 
   92         D1(printk(KERN_DEBUG "Scanned flash completely\n"));
   93         /* Now build the data map for each inode, marking obsoleted nodes
   94            as such, and also increase nlink of any children. */
   95         for_each_inode(i, c, ic) {
   96                 D1(printk(KERN_DEBUG "Pass 1: ino #%u\n", ic->ino));
   97                 ret = jffs2_build_inode_pass1(c, ic);
   98                 if (ret) {
   99                         D1(printk(KERN_WARNING "Eep. jffs2_build_inode_pass1 for ino %d returned %d\n", ic->ino, ret));
  100                         return ret;
  101                 }
  102         }
  103         D1(printk(KERN_DEBUG "Pass 1 complete\n"));
  104 
  105         /* Next, scan for inodes with nlink == 0 and remove them. If
  106            they were directories, then decrement the nlink of their
  107            children too, and repeat the scan. As that's going to be
  108            a fairly uncommon occurrence, it's not so evil to do it this
  109            way. Recursion bad. */
  110         do { 
  111                 D1(printk(KERN_DEBUG "Pass 2 (re)starting\n"));
  112                 ret = 0;
  113                 for_each_inode(i, c, ic) {
  114                         D1(printk(KERN_DEBUG "Pass 2: ino #%u, nlink %d, ic %p, nodes %p\n", ic->ino, ic->nlink, ic, ic->nodes));
  115                         if (ic->nlink)
  116                                 continue;
  117                         
  118                         ret = jffs2_build_remove_unlinked_inode(c, ic);
  119                         if (ret)
  120                                 break;
  121                 /* -EAGAIN means the inode's nlink was zero, so we deleted it,
  122                    and furthermore that it had children and their nlink has now
  123                    gone to zero too. So we have to restart the scan. */
  124                 } 
  125         } while(ret == -EAGAIN);
  126         
  127         D1(printk(KERN_DEBUG "Pass 2 complete\n"));
  128         
  129         /* Finally, we can scan again and free the dirent nodes and scan_info structs */
  130         for_each_inode(i, c, ic) {
  131                 struct jffs2_scan_info *scan = ic->scan;
  132                 struct jffs2_full_dirent *fd;
  133                 D1(printk(KERN_DEBUG "Pass 3: ino #%u, ic %p, nodes %p\n", ic->ino, ic, ic->nodes));
  134                 if (!scan) {
  135                         if (ic->nlink) {
  136                                 D1(printk(KERN_WARNING "Why no scan struct for ino #%u which has nlink %d?\n", ic->ino, ic->nlink));
  137                         }
  138                         continue;
  139                 }
  140                 ic->scan = NULL;
  141                 while(scan->dents) {
  142                         fd = scan->dents;
  143                         scan->dents = fd->next;
  144                         jffs2_free_full_dirent(fd);
  145                 }
  146                 kfree(scan);
  147         }
  148         D1(printk(KERN_DEBUG "Pass 3 complete\n"));
  149 
  150         return ret;
  151 }
  152         
  153 int jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
  154 {
  155         struct jffs2_tmp_dnode_info *tn;
  156         struct jffs2_full_dirent *fd;
  157         struct jffs2_node_frag *fraglist = NULL;
  158         struct jffs2_tmp_dnode_info *metadata = NULL;
  159 
  160         D1(printk(KERN_DEBUG "jffs2_build_inode building inode #%u\n", ic->ino));
  161         if (ic->ino > c->highest_ino)
  162                 c->highest_ino = ic->ino;
  163 
  164         if (!ic->scan->tmpnodes && ic->ino != 1) {
  165                 D1(printk(KERN_DEBUG "jffs2_build_inode: ino #%u has no data nodes!\n", ic->ino));
  166         }
  167         /* Build the list to make sure any obsolete nodes are marked as such */
  168         while(ic->scan->tmpnodes) {
  169                 tn = ic->scan->tmpnodes;
  170                 ic->scan->tmpnodes = tn->next;
  171                 
  172                 if (metadata && tn->version > metadata->version) {
  173                         D1(printk(KERN_DEBUG "jffs2_build_inode_pass1 ignoring old metadata at 0x%08x\n",
  174                                   metadata->fn->raw->flash_offset &~3));
  175                         
  176                         jffs2_free_full_dnode(metadata->fn);
  177                         jffs2_free_tmp_dnode_info(metadata);
  178                         metadata = NULL;
  179                 }
  180                         
  181                 if (tn->fn->size) {
  182                         jffs2_add_full_dnode_to_fraglist (c, &fraglist, tn->fn);
  183                         jffs2_free_tmp_dnode_info(tn);
  184                 } else {
  185                         if (!metadata) {
  186                                 metadata = tn;
  187                         } else {
  188                                 D1(printk(KERN_DEBUG "jffs2_build_inode_pass1 ignoring new metadata at 0x%08x\n",
  189                                           tn->fn->raw->flash_offset &~3));
  190                                 
  191                                 jffs2_free_full_dnode(tn->fn);
  192                                 jffs2_free_tmp_dnode_info(tn);
  193                         }
  194                 }
  195         }
  196                 
  197         /* OK. Now clear up */
  198         if (metadata) {
  199                 jffs2_free_full_dnode(metadata->fn);
  200                 jffs2_free_tmp_dnode_info(metadata);
  201         }
  202         metadata = NULL;
  203         
  204         while (fraglist) {
  205                 struct jffs2_node_frag *frag;
  206                 frag = fraglist;
  207                 fraglist = fraglist->next;
  208                 
  209                 if (frag->node && !(--frag->node->frags)) {
  210                         jffs2_free_full_dnode(frag->node);
  211                 }
  212                 jffs2_free_node_frag(frag);
  213         }
  214 
  215         /* Now for each child, increase nlink */
  216         for(fd=ic->scan->dents; fd; fd = fd->next) {
  217                 struct jffs2_inode_cache *child_ic;
  218                 if (!fd->ino)
  219                         continue;
  220 
  221                 child_ic = jffs2_get_ino_cache(c, fd->ino);
  222                 if (!child_ic) {
  223                         printk(KERN_NOTICE "Eep. Child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n",
  224                                   fd->name, fd->ino, ic->ino);
  225                         continue;
  226                 }
  227 
  228                 if (child_ic->nlink++ && fd->type == DT_DIR) {
  229                         printk(KERN_NOTICE "Child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n", fd->name, fd->ino, ic->ino);
  230                         if (fd->ino == 1 && ic->ino == 1) {
  231                                 printk(KERN_NOTICE "This is mostly harmless, and probably caused by creating a JFFS2 image\n");
  232                                 printk(KERN_NOTICE "using a buggy version of mkfs.jffs2. Use at least v1.17.\n");
  233                         }
  234                         /* What do we do about it? */
  235                 }
  236                 D1(printk(KERN_DEBUG "Increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino));
  237                 /* Can't free them. We might need them in pass 2 */
  238         }
  239         return 0;
  240 }
  241 
  242 int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
  243 {
  244         struct jffs2_raw_node_ref *raw;
  245         struct jffs2_full_dirent *fd;
  246         int ret = 0;
  247 
  248         if(!ic->scan) {
  249                 D1(printk(KERN_DEBUG "ino #%u was already removed\n", ic->ino));
  250                 return 0;
  251         }
  252 
  253         D1(printk(KERN_DEBUG "JFFS2: Removing ino #%u with nlink == zero.\n", ic->ino));
  254         
  255         for (raw = ic->nodes; raw != (void *)ic; raw = raw->next_in_ino) {
  256                 D1(printk(KERN_DEBUG "obsoleting node at 0x%08x\n", raw->flash_offset&~3));
  257                 jffs2_mark_node_obsolete(c, raw);
  258         }
  259 
  260         if (ic->scan->dents) {
  261                 printk(KERN_NOTICE "Inode #%u was a directory with children - removing those too...\n", ic->ino);
  262         
  263                 while(ic->scan->dents) {
  264                         struct jffs2_inode_cache *child_ic;
  265 
  266                         fd = ic->scan->dents;
  267                         ic->scan->dents = fd->next;
  268 
  269                         D1(printk(KERN_DEBUG "Removing child \"%s\", ino #%u\n",
  270                                   fd->name, fd->ino));
  271                         
  272                         child_ic = jffs2_get_ino_cache(c, fd->ino);
  273                         if (!child_ic) {
  274                                 printk(KERN_NOTICE "Cannot remove child \"%s\", ino #%u, because it doesn't exist\n", fd->name, fd->ino);
  275                                 continue;
  276                         }
  277                         jffs2_free_full_dirent(fd);
  278                         child_ic->nlink--;
  279                 }
  280                 ret = -EAGAIN;
  281         }
  282         kfree(ic->scan);
  283         ic->scan = NULL;
  284         //      jffs2_del_ino_cache(c, ic);
  285         //      jffs2_free_inode_cache(ic);
  286         return ret;
  287 }

Cache object: 3c48488c999bf48864bf07644a670768


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.