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/nodemgmt.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: nodemgmt.c,v 1.45.2.1 2002/02/23 14:13:34 dwmw2 Exp $
   35  *
   36  */
   37 
   38 #include <linux/kernel.h>
   39 #include <linux/slab.h>
   40 #include <linux/jffs2.h>
   41 #include <linux/mtd/mtd.h>
   42 #include <linux/interrupt.h>
   43 #include "nodelist.h"
   44 
   45 /**
   46  *      jffs2_reserve_space - request physical space to write nodes to flash
   47  *      @c: superblock info
   48  *      @minsize: Minimum acceptable size of allocation
   49  *      @ofs: Returned value of node offset
   50  *      @len: Returned value of allocation length
   51  *      @prio: Allocation type - ALLOC_{NORMAL,DELETION}
   52  *
   53  *      Requests a block of physical space on the flash. Returns zero for success
   54  *      and puts 'ofs' and 'len' into the appriopriate place, or returns -ENOSPC
   55  *      or other error if appropriate.
   56  *
   57  *      If it returns zero, jffs2_reserve_space() also downs the per-filesystem
   58  *      allocation semaphore, to prevent more than one allocation from being
   59  *      active at any time. The semaphore is later released by jffs2_commit_allocation()
   60  *
   61  *      jffs2_reserve_space() may trigger garbage collection in order to make room
   62  *      for the requested allocation.
   63  */
   64 
   65 static int jffs2_do_reserve_space(struct jffs2_sb_info *c,  __u32 minsize, __u32 *ofs, __u32 *len);
   66 
   67 int jffs2_reserve_space(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u32 *len, int prio)
   68 {
   69         int ret = -EAGAIN;
   70         int blocksneeded = JFFS2_RESERVED_BLOCKS_WRITE;
   71         /* align it */
   72         minsize = PAD(minsize);
   73 
   74         if (prio == ALLOC_DELETION)
   75                 blocksneeded = JFFS2_RESERVED_BLOCKS_DELETION;
   76 
   77         D1(printk(KERN_DEBUG "jffs2_reserve_space(): Requested 0x%x bytes\n", minsize));
   78         down(&c->alloc_sem);
   79 
   80         D1(printk(KERN_DEBUG "jffs2_reserve_space(): alloc sem got\n"));
   81 
   82         spin_lock_bh(&c->erase_completion_lock);
   83 
   84         /* this needs a little more thought */
   85         while(ret == -EAGAIN) {
   86                 while(c->nr_free_blocks + c->nr_erasing_blocks < blocksneeded) {
   87                         int ret;
   88 
   89                         up(&c->alloc_sem);
   90                         if (c->dirty_size < c->sector_size) {
   91                                 D1(printk(KERN_DEBUG "Short on space, but total dirty size 0x%08x < sector size 0x%08x, so -ENOSPC\n", c->dirty_size, c->sector_size));
   92                                 spin_unlock_bh(&c->erase_completion_lock);
   93                                 return -ENOSPC;
   94                         }
   95                         D1(printk(KERN_DEBUG "Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)\n",
   96                                   c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size,
   97                                   c->free_size + c->dirty_size + c->used_size + c->erasing_size + c->bad_size, c->flash_size));
   98                         spin_unlock_bh(&c->erase_completion_lock);
   99                         
  100                         ret = jffs2_garbage_collect_pass(c);
  101                         if (ret)
  102                                 return ret;
  103 
  104                         if (current->need_resched)
  105                                 schedule();
  106 
  107                         if (signal_pending(current))
  108                                 return -EINTR;
  109 
  110                         down(&c->alloc_sem);
  111                         spin_lock_bh(&c->erase_completion_lock);
  112                 }
  113 
  114                 ret = jffs2_do_reserve_space(c, minsize, ofs, len);
  115                 if (ret) {
  116                         D1(printk(KERN_DEBUG "jffs2_reserve_space: ret is %d\n", ret));
  117                 }
  118         }
  119         spin_unlock_bh(&c->erase_completion_lock);
  120         if (ret)
  121                 up(&c->alloc_sem);
  122         return ret;
  123 }
  124 
  125 int jffs2_reserve_space_gc(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u32 *len)
  126 {
  127         int ret = -EAGAIN;
  128         minsize = PAD(minsize);
  129 
  130         D1(printk(KERN_DEBUG "jffs2_reserve_space_gc(): Requested 0x%x bytes\n", minsize));
  131 
  132         spin_lock_bh(&c->erase_completion_lock);
  133         while(ret == -EAGAIN) {
  134                 ret = jffs2_do_reserve_space(c, minsize, ofs, len);
  135                 if (ret) {
  136                         D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret));
  137                 }
  138         }
  139         spin_unlock_bh(&c->erase_completion_lock);
  140         return ret;
  141 }
  142 
  143 /* Called with alloc sem _and_ erase_completion_lock */
  144 static int jffs2_do_reserve_space(struct jffs2_sb_info *c,  __u32 minsize, __u32 *ofs, __u32 *len)
  145 {
  146         struct jffs2_eraseblock *jeb = c->nextblock;
  147         
  148  restart:
  149         if (jeb && minsize > jeb->free_size) {
  150                 /* Skip the end of this block and file it as having some dirty space */
  151                 c->dirty_size += jeb->free_size;
  152                 c->free_size -= jeb->free_size;
  153                 jeb->dirty_size += jeb->free_size;
  154                 jeb->free_size = 0;
  155                 D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
  156                           jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
  157                 list_add_tail(&jeb->list, &c->dirty_list);
  158                 c->nextblock = jeb = NULL;
  159         }
  160         
  161         if (!jeb) {
  162                 struct list_head *next;
  163                 /* Take the next block off the 'free' list */
  164 
  165                 if (list_empty(&c->free_list)) {
  166 
  167                         DECLARE_WAITQUEUE(wait, current);
  168                         
  169                         if (!c->nr_erasing_blocks) {
  170 //                      if (list_empty(&c->erasing_list) && list_empty(&c->erase_pending_list) && list_empty(c->erase_complete_list)) {
  171                                 /* Ouch. We're in GC, or we wouldn't have got here.
  172                                    And there's no space left. At all. */
  173                                 printk(KERN_CRIT "Argh. No free space left for GC. nr_erasing_blocks is %d. nr_free_blocks is %d. (erasingempty: %s, erasependingempty: %s)\n", 
  174                                        c->nr_erasing_blocks, c->nr_free_blocks, list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no");
  175                                 return -ENOSPC;
  176                         }
  177                         /* Make sure this can't deadlock. Someone has to start the erases
  178                            of erase_pending blocks */
  179                         set_current_state(TASK_INTERRUPTIBLE);
  180                         add_wait_queue(&c->erase_wait, &wait);
  181                         D1(printk(KERN_DEBUG "Waiting for erases to complete. erasing_blocks is %d. (erasingempty: %s, erasependingempty: %s)\n", 
  182                                   c->nr_erasing_blocks, list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no"));
  183                         if (!list_empty(&c->erase_pending_list)) {
  184                                 D1(printk(KERN_DEBUG "Triggering pending erases\n"));
  185                                 jffs2_erase_pending_trigger(c);
  186                         }
  187                         spin_unlock_bh(&c->erase_completion_lock);
  188                         schedule();
  189                         remove_wait_queue(&c->erase_wait, &wait);
  190                         spin_lock_bh(&c->erase_completion_lock);
  191                         if (signal_pending(current)) {
  192                                 return -EINTR;
  193                         }
  194                         /* An erase may have failed, decreasing the
  195                            amount of free space available. So we must
  196                            restart from the beginning */
  197                         return -EAGAIN;
  198                 }
  199 
  200                 next = c->free_list.next;
  201                 list_del(next);
  202                 c->nextblock = jeb = list_entry(next, struct jffs2_eraseblock, list);
  203                 c->nr_free_blocks--;
  204                 if (jeb->free_size != c->sector_size - sizeof(struct jffs2_unknown_node)) {
  205                         printk(KERN_WARNING "Eep. Block 0x%08x taken from free_list had free_size of 0x%08x!!\n", jeb->offset, jeb->free_size);
  206                         goto restart;
  207                 }
  208         }
  209         /* OK, jeb (==c->nextblock) is now pointing at a block which definitely has
  210            enough space */
  211         *ofs = jeb->offset + (c->sector_size - jeb->free_size);
  212         *len = jeb->free_size;
  213         D1(printk(KERN_DEBUG "jffs2_do_reserve_space(): Giving 0x%x bytes at 0x%x\n", *len, *ofs));
  214         return 0;
  215 }
  216 
  217 /**
  218  *      jffs2_add_physical_node_ref - add a physical node reference to the list
  219  *      @c: superblock info
  220  *      @ofs: physical location of this physical node
  221  *      @len: length of this physical node
  222  *      @ino: inode number with which this physical node is associated
  223  *
  224  *      Should only be used to report nodes for which space has been allocated 
  225  *      by jffs2_reserve_space.
  226  *
  227  *      Must be called with the alloc_sem held.
  228  */
  229  
  230 int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new, __u32 len, int dirty)
  231 {
  232         struct jffs2_eraseblock *jeb;
  233 
  234         len = PAD(len);
  235         jeb = &c->blocks[(new->flash_offset & ~3) / c->sector_size];
  236         D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x, size 0x%x\n", new->flash_offset & ~3, len));
  237 #if 1
  238         if (jeb != c->nextblock || (new->flash_offset & ~3) != jeb->offset + (c->sector_size - jeb->free_size)) {
  239                 printk(KERN_WARNING "argh. node added in wrong place\n");
  240                 jffs2_free_raw_node_ref(new);
  241                 return -EINVAL;
  242         }
  243 #endif
  244         if (!jeb->first_node)
  245                 jeb->first_node = new;
  246         if (jeb->last_node)
  247                 jeb->last_node->next_phys = new;
  248         jeb->last_node = new;
  249 
  250         spin_lock_bh(&c->erase_completion_lock);
  251         jeb->free_size -= len;
  252         c->free_size -= len;
  253         if (dirty) {
  254                 new->flash_offset |= 1;
  255                 jeb->dirty_size += len;
  256                 c->dirty_size += len;
  257         } else {
  258                 jeb->used_size += len;
  259                 c->used_size += len;
  260         }
  261         spin_unlock_bh(&c->erase_completion_lock);
  262         if (!jeb->free_size && !jeb->dirty_size) {
  263                 /* If it lives on the dirty_list, jffs2_reserve_space will put it there */
  264                 D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
  265                           jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
  266                 list_add_tail(&jeb->list, &c->clean_list);
  267                 c->nextblock = NULL;
  268         }
  269         ACCT_SANITY_CHECK(c,jeb);
  270         ACCT_PARANOIA_CHECK(jeb);
  271 
  272         return 0;
  273 }
  274 
  275 
  276 void jffs2_complete_reservation(struct jffs2_sb_info *c)
  277 {
  278         D1(printk(KERN_DEBUG "jffs2_complete_reservation()\n"));
  279         jffs2_garbage_collect_trigger(c);
  280         up(&c->alloc_sem);
  281 }
  282 
  283 void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref)
  284 {
  285         struct jffs2_eraseblock *jeb;
  286         int blocknr;
  287         struct jffs2_unknown_node n;
  288         int ret;
  289         ssize_t retlen;
  290 
  291         if(!ref) {
  292                 printk(KERN_NOTICE "EEEEEK. jffs2_mark_node_obsolete called with NULL node\n");
  293                 return;
  294         }
  295         if (ref->flash_offset & 1) {
  296                 D1(printk(KERN_DEBUG "jffs2_mark_node_obsolete called with already obsolete node at 0x%08x\n", ref->flash_offset &~3));
  297                 return;
  298         }
  299         blocknr = ref->flash_offset / c->sector_size;
  300         if (blocknr >= c->nr_blocks) {
  301                 printk(KERN_NOTICE "raw node at 0x%08x is off the end of device!\n", ref->flash_offset);
  302                 BUG();
  303         }
  304         jeb = &c->blocks[blocknr];
  305         if (jeb->used_size < ref->totlen) {
  306                 printk(KERN_NOTICE "raw node of size 0x%08x freed from erase block %d at 0x%08x, but used_size was already 0x%08x\n",
  307                        ref->totlen, blocknr, ref->flash_offset, jeb->used_size);
  308                 BUG();
  309         }
  310 
  311         spin_lock_bh(&c->erase_completion_lock);
  312         jeb->used_size -= ref->totlen;
  313         jeb->dirty_size += ref->totlen;
  314         c->used_size -= ref->totlen;
  315         c->dirty_size += ref->totlen;
  316         ref->flash_offset |= 1;
  317         
  318         ACCT_SANITY_CHECK(c, jeb);
  319 
  320         ACCT_PARANOIA_CHECK(jeb);
  321 
  322         if (c->flags & JFFS2_SB_FLAG_MOUNTING) {
  323                 /* Mount in progress. Don't muck about with the block
  324                    lists because they're not ready yet, and don't actually
  325                    obliterate nodes that look obsolete. If they weren't 
  326                    marked obsolete on the flash at the time they _became_
  327                    obsolete, there was probably a reason for that. */
  328                 spin_unlock_bh(&c->erase_completion_lock);
  329                 return;
  330         }
  331         if (jeb == c->nextblock) {
  332                 D2(printk(KERN_DEBUG "Not moving nextblock 0x%08x to dirty/erase_pending list\n", jeb->offset));
  333         } else if (jeb == c->gcblock) {
  334                 D2(printk(KERN_DEBUG "Not moving gcblock 0x%08x to dirty/erase_pending list\n", jeb->offset));
  335 #if 0 /* We no longer do this here. It can screw the wear levelling. If you have a lot of static
  336          data and a few blocks free, and you just create new files and keep deleting/overwriting
  337          them, then you'd keep erasing and reusing those blocks without ever moving stuff around.
  338          So we leave completely obsoleted blocks on the dirty_list and let the GC delete them 
  339          when it finds them there. That way, we still get the 'once in a while, take a clean block'
  340          to spread out the flash usage */
  341         } else if (!jeb->used_size) {
  342                 D1(printk(KERN_DEBUG "Eraseblock at 0x%08x completely dirtied. Removing from (dirty?) list...\n", jeb->offset));
  343                 list_del(&jeb->list);
  344                 D1(printk(KERN_DEBUG "...and adding to erase_pending_list\n"));
  345                 list_add_tail(&jeb->list, &c->erase_pending_list);
  346                 c->nr_erasing_blocks++;
  347                 jffs2_erase_pending_trigger(c);
  348                 //              OFNI_BS_2SFFJ(c)->s_dirt = 1;
  349                 D1(printk(KERN_DEBUG "Done OK\n"));
  350 #endif
  351         } else if (jeb->dirty_size == ref->totlen) {
  352                 D1(printk(KERN_DEBUG "Eraseblock at 0x%08x is freshly dirtied. Removing from clean list...\n", jeb->offset));
  353                 list_del(&jeb->list);
  354                 D1(printk(KERN_DEBUG "...and adding to dirty_list\n"));
  355                 list_add_tail(&jeb->list, &c->dirty_list);
  356         }
  357         spin_unlock_bh(&c->erase_completion_lock);
  358 
  359         if (c->mtd->type != MTD_NORFLASH && c->mtd->type != MTD_RAM)
  360                 return;
  361         if (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY)
  362                 return;
  363 
  364         D1(printk(KERN_DEBUG "obliterating obsoleted node at 0x%08x\n", ref->flash_offset &~3));
  365         ret = c->mtd->read(c->mtd, ref->flash_offset &~3, sizeof(n), &retlen, (char *)&n);
  366         if (ret) {
  367                 printk(KERN_WARNING "Read error reading from obsoleted node at 0x%08x: %d\n", ref->flash_offset &~3, ret);
  368                 return;
  369         }
  370         if (retlen != sizeof(n)) {
  371                 printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %d\n", ref->flash_offset &~3, retlen);
  372                 return;
  373         }
  374         if (PAD(n.totlen) != PAD(ref->totlen)) {
  375                 printk(KERN_WARNING "Node totlen on flash (0x%08x) != totlen in node ref (0x%08x)\n", n.totlen, ref->totlen);
  376                 return;
  377         }
  378         if (!(n.nodetype & JFFS2_NODE_ACCURATE)) {
  379                 D1(printk(KERN_DEBUG "Node at 0x%08x was already marked obsolete (nodetype 0x%04x\n", ref->flash_offset &~3, n.nodetype));
  380                 return;
  381         }
  382         n.nodetype &= ~JFFS2_NODE_ACCURATE;
  383         ret = c->mtd->write(c->mtd, ref->flash_offset&~3, sizeof(n), &retlen, (char *)&n);
  384         if (ret) {
  385                 printk(KERN_WARNING "Write error in obliterating obsoleted node at 0x%08x: %d\n", ref->flash_offset &~3, ret);
  386                 return;
  387         }
  388         if (retlen != sizeof(n)) {
  389                 printk(KERN_WARNING "Short write in obliterating obsoleted node at 0x%08x: %d\n", ref->flash_offset &~3, retlen);
  390                 return;
  391         }
  392 }

Cache object: 3b0bc4348a97fffe8e2072d5a5f9ff04


[ 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.