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/gc.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: gc.c,v 1.52.2.5 2002/10/10 13:18:38 dwmw2 Exp $
   35  *
   36  */
   37 
   38 #include <linux/kernel.h>
   39 #include <linux/mtd/mtd.h>
   40 #include <linux/slab.h>
   41 #include <linux/jffs2.h>
   42 #include <linux/sched.h>
   43 #include <linux/interrupt.h>
   44 #include <linux/pagemap.h>
   45 #include "nodelist.h"
   46 #include <linux/crc32.h>
   47 
   48 static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 
   49                                         struct inode *inode, struct jffs2_full_dnode *fd);
   50 static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 
   51                                         struct inode *inode, struct jffs2_full_dirent *fd);
   52 static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 
   53                                         struct inode *inode, struct jffs2_full_dirent *fd);
   54 static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
   55                                       struct inode *indeo, struct jffs2_full_dnode *fn,
   56                                       __u32 start, __u32 end);
   57 static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
   58                                        struct inode *inode, struct jffs2_full_dnode *fn,
   59                                        __u32 start, __u32 end);
   60 
   61 /* Called with erase_completion_lock held */
   62 static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c)
   63 {
   64         struct jffs2_eraseblock *ret;
   65         struct list_head *nextlist = NULL;
   66 
   67         /* Pick an eraseblock to garbage collect next. This is where we'll
   68            put the clever wear-levelling algorithms. Eventually.  */
   69         if (!list_empty(&c->bad_used_list) && c->nr_free_blocks > JFFS2_RESERVED_BLOCKS_GCBAD) {
   70                 D1(printk(KERN_DEBUG "Picking block from bad_used_list to GC next\n"));
   71                 nextlist = &c->bad_used_list;
   72         } else if (jiffies % 100 && !list_empty(&c->dirty_list)) {
   73                 /* Most of the time, pick one off the dirty list */
   74                 D1(printk(KERN_DEBUG "Picking block from dirty_list to GC next\n"));
   75                 nextlist = &c->dirty_list;
   76         } else if (!list_empty(&c->clean_list)) {
   77                 D1(printk(KERN_DEBUG "Picking block from clean_list to GC next\n"));
   78                 nextlist = &c->clean_list;
   79         } else if (!list_empty(&c->dirty_list)) {
   80                 D1(printk(KERN_DEBUG "Picking block from dirty_list to GC next (clean_list was empty)\n"));
   81 
   82                 nextlist = &c->dirty_list;
   83         } else {
   84                 /* Eep. Both were empty */
   85                 printk(KERN_NOTICE "jffs2: No clean _or_ dirty blocks to GC from! Where are they all?\n");
   86                 return NULL;
   87         }
   88 
   89         ret = list_entry(nextlist->next, struct jffs2_eraseblock, list);
   90         list_del(&ret->list);
   91         c->gcblock = ret;
   92         ret->gc_node = ret->first_node;
   93         if (!ret->gc_node) {
   94                 printk(KERN_WARNING "Eep. ret->gc_node for block at 0x%08x is NULL\n", ret->offset);
   95                 BUG();
   96         }
   97         return ret;
   98 }
   99 
  100 /* jffs2_garbage_collect_pass
  101  * Make a single attempt to progress GC. Move one node, and possibly
  102  * start erasing one eraseblock.
  103  */
  104 int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
  105 {
  106         struct jffs2_eraseblock *jeb;
  107         struct jffs2_inode_info *f;
  108         struct jffs2_raw_node_ref *raw;
  109         struct jffs2_node_frag *frag;
  110         struct jffs2_full_dnode *fn = NULL;
  111         struct jffs2_full_dirent *fd;
  112         __u32 start = 0, end = 0, nrfrags = 0;
  113         __u32 inum;
  114         struct inode *inode;
  115         int ret = 0;
  116 
  117         if (down_interruptible(&c->alloc_sem))
  118                 return -EINTR;
  119 
  120         spin_lock_bh(&c->erase_completion_lock);
  121 
  122         /* First, work out which block we're garbage-collecting */
  123         jeb = c->gcblock;
  124 
  125         if (!jeb)
  126                 jeb = jffs2_find_gc_block(c);
  127 
  128         if (!jeb) {
  129                 printk(KERN_NOTICE "jffs2: Couldn't find erase block to garbage collect!\n");
  130                 spin_unlock_bh(&c->erase_completion_lock);
  131                 up(&c->alloc_sem);
  132                 return -EIO;
  133         }
  134 
  135         D1(printk(KERN_DEBUG "garbage collect from block at phys 0x%08x\n", jeb->offset));
  136 
  137         if (!jeb->used_size) {
  138                 up(&c->alloc_sem);
  139                 goto eraseit;
  140         }
  141 
  142         raw = jeb->gc_node;
  143                         
  144         while(raw->flash_offset & 1) {
  145                 D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", raw->flash_offset &~3));
  146                 jeb->gc_node = raw = raw->next_phys;
  147                 if (!raw) {
  148                         printk(KERN_WARNING "eep. End of raw list while still supposedly nodes to GC\n");
  149                         printk(KERN_WARNING "erase block at 0x%08x. free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x\n", 
  150                                jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size);
  151                         spin_unlock_bh(&c->erase_completion_lock);
  152                         up(&c->alloc_sem);
  153                         BUG();
  154                 }
  155         }
  156         D1(printk(KERN_DEBUG "Going to garbage collect node at 0x%08x\n", raw->flash_offset &~3));
  157         if (!raw->next_in_ino) {
  158                 /* Inode-less node. Clean marker, snapshot or something like that */
  159                 spin_unlock_bh(&c->erase_completion_lock);
  160                 jffs2_mark_node_obsolete(c, raw);
  161                 up(&c->alloc_sem);
  162                 goto eraseit_lock;
  163         }
  164                                                      
  165         inum = jffs2_raw_ref_to_inum(raw);
  166         D1(printk(KERN_DEBUG "Inode number is #%u\n", inum));
  167 
  168         spin_unlock_bh(&c->erase_completion_lock);
  169 
  170         D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass collecting from block @0x%08x. Node @0x%08x, ino #%u\n", jeb->offset, raw->flash_offset&~3, inum));
  171 
  172         inode = iget(OFNI_BS_2SFFJ(c), inum);
  173         if (is_bad_inode(inode)) {
  174                 printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u\n", inum);
  175                 /* NB. This will happen again. We need to do something appropriate here. */
  176                 up(&c->alloc_sem);
  177                 iput(inode);
  178                 return -EIO;
  179         }
  180 
  181         f = JFFS2_INODE_INFO(inode);
  182         down(&f->sem);
  183         /* Now we have the lock for this inode. Check that it's still the one at the head
  184            of the list. */
  185 
  186         if (raw->flash_offset & 1) {
  187                 D1(printk(KERN_DEBUG "node to be GC'd was obsoleted in the meantime.\n"));
  188                 /* They'll call again */
  189                 goto upnout;
  190         }
  191         /* OK. Looks safe. And nobody can get us now because we have the semaphore. Move the block */
  192         if (f->metadata && f->metadata->raw == raw) {
  193                 fn = f->metadata;
  194                 ret = jffs2_garbage_collect_metadata(c, jeb, inode, fn);
  195                 goto upnout;
  196         }
  197         
  198         for (frag = f->fraglist; frag; frag = frag->next) {
  199                 if (frag->node && frag->node->raw == raw) {
  200                         fn = frag->node;
  201                         end = frag->ofs + frag->size;
  202                         if (!nrfrags++)
  203                                 start = frag->ofs;
  204                         if (nrfrags == frag->node->frags)
  205                                 break; /* We've found them all */
  206                 }
  207         }
  208         if (fn) {
  209                 /* We found a datanode. Do the GC */
  210                 if((start >> PAGE_CACHE_SHIFT) < ((end-1) >> PAGE_CACHE_SHIFT)) {
  211                         /* It crosses a page boundary. Therefore, it must be a hole. */
  212                         ret = jffs2_garbage_collect_hole(c, jeb, inode, fn, start, end);
  213                 } else {
  214                         /* It could still be a hole. But we GC the page this way anyway */
  215                         ret = jffs2_garbage_collect_dnode(c, jeb, inode, fn, start, end);
  216                 }
  217                 goto upnout;
  218         }
  219         
  220         /* Wasn't a dnode. Try dirent */
  221         for (fd = f->dents; fd; fd=fd->next) {
  222                 if (fd->raw == raw)
  223                         break;
  224         }
  225 
  226         if (fd && fd->ino) {
  227                 ret = jffs2_garbage_collect_dirent(c, jeb, inode, fd);
  228         } else if (fd) {
  229                 ret = jffs2_garbage_collect_deletion_dirent(c, jeb, inode, fd);
  230         } else {
  231                 printk(KERN_WARNING "Raw node at 0x%08x wasn't in node lists for ino #%lu\n", raw->flash_offset&~3, inode->i_ino);
  232                 if (raw->flash_offset & 1) {
  233                         printk(KERN_WARNING "But it's obsolete so we don't mind too much\n");
  234                 } else {
  235                         ret = -EIO;
  236                 }
  237         }
  238  upnout:
  239         up(&f->sem);
  240         up(&c->alloc_sem);
  241         iput(inode);
  242 
  243  eraseit_lock:
  244         /* If we've finished this block, start it erasing */
  245         spin_lock_bh(&c->erase_completion_lock);
  246 
  247  eraseit:
  248         if (c->gcblock && !c->gcblock->used_size) {
  249                 D1(printk(KERN_DEBUG "Block at 0x%08x completely obsoleted by GC. Moving to erase_pending_list\n", c->gcblock->offset));
  250                 /* We're GC'ing an empty block? */
  251                 list_add_tail(&c->gcblock->list, &c->erase_pending_list);
  252                 c->gcblock = NULL;
  253                 c->nr_erasing_blocks++;
  254                 jffs2_erase_pending_trigger(c);
  255         }
  256         spin_unlock_bh(&c->erase_completion_lock);
  257 
  258         return ret;
  259 }
  260 
  261 static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 
  262                                         struct inode *inode, struct jffs2_full_dnode *fn)
  263 {
  264         struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
  265         struct jffs2_full_dnode *new_fn;
  266         struct jffs2_raw_inode ri;
  267         unsigned short dev;
  268         char *mdata = NULL, mdatalen = 0;
  269         __u32 alloclen, phys_ofs;
  270         int ret;
  271 
  272         if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
  273                 /* For these, we don't actually need to read the old node */
  274                 dev =  (MAJOR(to_kdev_t(inode->i_rdev)) << 8) | 
  275                         MINOR(to_kdev_t(inode->i_rdev));
  276                 mdata = (char *)&dev;
  277                 mdatalen = sizeof(dev);
  278                 D1(printk(KERN_DEBUG "jffs2_garbage_collect_metadata(): Writing %d bytes of kdev_t\n", mdatalen));
  279         } else if (S_ISLNK(inode->i_mode)) {
  280                 mdatalen = fn->size;
  281                 mdata = kmalloc(fn->size, GFP_KERNEL);
  282                 if (!mdata) {
  283                         printk(KERN_WARNING "kmalloc of mdata failed in jffs2_garbage_collect_metadata()\n");
  284                         return -ENOMEM;
  285                 }
  286                 ret = jffs2_read_dnode(c, fn, mdata, 0, mdatalen);
  287                 if (ret) {
  288                         printk(KERN_WARNING "read of old metadata failed in jffs2_garbage_collect_metadata(): %d\n", ret);
  289                         kfree(mdata);
  290                         return ret;
  291                 }
  292                 D1(printk(KERN_DEBUG "jffs2_garbage_collect_metadata(): Writing %d bites of symlink target\n", mdatalen));
  293 
  294         }
  295         
  296         ret = jffs2_reserve_space_gc(c, sizeof(ri) + mdatalen, &phys_ofs, &alloclen);
  297         if (ret) {
  298                 printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_metadata failed: %d\n",
  299                        sizeof(ri)+ mdatalen, ret);
  300                 goto out;
  301         }
  302         
  303         memset(&ri, 0, sizeof(ri));
  304         ri.magic = JFFS2_MAGIC_BITMASK;
  305         ri.nodetype = JFFS2_NODETYPE_INODE;
  306         ri.totlen = sizeof(ri) + mdatalen;
  307         ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4);
  308 
  309         ri.ino = inode->i_ino;
  310         ri.version = ++f->highest_version;
  311         ri.mode = inode->i_mode;
  312         ri.uid = inode->i_uid;
  313         ri.gid = inode->i_gid;
  314         ri.isize = inode->i_size;
  315         ri.atime = inode->i_atime;
  316         ri.ctime = inode->i_ctime;
  317         ri.mtime = inode->i_mtime;
  318         ri.offset = 0;
  319         ri.csize = mdatalen;
  320         ri.dsize = mdatalen;
  321         ri.compr = JFFS2_COMPR_NONE;
  322         ri.node_crc = crc32(0, &ri, sizeof(ri)-8);
  323         ri.data_crc = crc32(0, mdata, mdatalen);
  324 
  325         new_fn = jffs2_write_dnode(inode, &ri, mdata, mdatalen, phys_ofs, NULL);
  326 
  327         if (IS_ERR(new_fn)) {
  328                 printk(KERN_WARNING "Error writing new dnode: %ld\n", PTR_ERR(new_fn));
  329                 ret = PTR_ERR(new_fn);
  330                 goto out;
  331         }
  332         jffs2_mark_node_obsolete(c, fn->raw);
  333         jffs2_free_full_dnode(fn);
  334         f->metadata = new_fn;
  335  out:
  336         if (S_ISLNK(inode->i_mode))
  337                 kfree(mdata);
  338         return ret;
  339 }
  340 
  341 static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 
  342                                         struct inode *inode, struct jffs2_full_dirent *fd)
  343 {
  344         struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
  345         struct jffs2_full_dirent *new_fd;
  346         struct jffs2_raw_dirent rd;
  347         __u32 alloclen, phys_ofs;
  348         int ret;
  349 
  350         rd.magic = JFFS2_MAGIC_BITMASK;
  351         rd.nodetype = JFFS2_NODETYPE_DIRENT;
  352         rd.nsize = strlen(fd->name);
  353         rd.totlen = sizeof(rd) + rd.nsize;
  354         rd.hdr_crc = crc32(0, &rd, sizeof(struct jffs2_unknown_node)-4);
  355 
  356         rd.pino = inode->i_ino;
  357         rd.version = ++f->highest_version;
  358         rd.ino = fd->ino;
  359         rd.mctime = max(inode->i_mtime, inode->i_ctime);
  360         rd.type = fd->type;
  361         rd.node_crc = crc32(0, &rd, sizeof(rd)-8);
  362         rd.name_crc = crc32(0, fd->name, rd.nsize);
  363         
  364         ret = jffs2_reserve_space_gc(c, sizeof(rd)+rd.nsize, &phys_ofs, &alloclen);
  365         if (ret) {
  366                 printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_dirent failed: %d\n",
  367                        sizeof(rd)+rd.nsize, ret);
  368                 return ret;
  369         }
  370         new_fd = jffs2_write_dirent(inode, &rd, fd->name, rd.nsize, phys_ofs, NULL);
  371 
  372         if (IS_ERR(new_fd)) {
  373                 printk(KERN_WARNING "jffs2_write_dirent in garbage_collect_dirent failed: %ld\n", PTR_ERR(new_fd));
  374                 return PTR_ERR(new_fd);
  375         }
  376         jffs2_add_fd_to_list(c, new_fd, &f->dents);
  377         return 0;
  378 }
  379 
  380 static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 
  381                                         struct inode *inode, struct jffs2_full_dirent *fd)
  382 {
  383         struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
  384         struct jffs2_full_dirent **fdp = &f->dents;
  385         int found = 0;
  386 
  387         /* FIXME: When we run on NAND flash, we need to work out whether
  388            this deletion dirent is still needed to actively delete a
  389            'real' dirent with the same name that's still somewhere else
  390            on the flash. For now, we know that we've actually obliterated
  391            all the older dirents when they became obsolete, so we didn't
  392            really need to write the deletion to flash in the first place.
  393         */
  394         while (*fdp) {
  395                 if ((*fdp) == fd) {
  396                         found = 1;
  397                         *fdp = fd->next;
  398                         break;
  399                 }
  400                 fdp = &(*fdp)->next;
  401         }
  402         if (!found) {
  403                 printk(KERN_WARNING "Deletion dirent \"%s\" not found in list for ino #%lu\n", fd->name, inode->i_ino);
  404         }
  405         jffs2_mark_node_obsolete(c, fd->raw);
  406         jffs2_free_full_dirent(fd);
  407         return 0;
  408 }
  409 
  410 static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
  411                                       struct inode *inode, struct jffs2_full_dnode *fn,
  412                                       __u32 start, __u32 end)
  413 {
  414         struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
  415         struct jffs2_raw_inode ri;
  416         struct jffs2_node_frag *frag;
  417         struct jffs2_full_dnode *new_fn;
  418         __u32 alloclen, phys_ofs;
  419         int ret;
  420 
  421         D1(printk(KERN_DEBUG "Writing replacement hole node for ino #%lu from offset 0x%x to 0x%x\n",
  422                   inode->i_ino, start, end));
  423         
  424         memset(&ri, 0, sizeof(ri));
  425 
  426         if(fn->frags > 1) {
  427                 size_t readlen;
  428                 __u32 crc;
  429                 /* It's partially obsoleted by a later write. So we have to 
  430                    write it out again with the _same_ version as before */
  431                 ret = c->mtd->read(c->mtd, fn->raw->flash_offset & ~3, sizeof(ri), &readlen, (char *)&ri);
  432                 if (readlen != sizeof(ri) || ret) {
  433                         printk(KERN_WARNING "Node read failed in jffs2_garbage_collect_hole. Ret %d, retlen %d. Data will be lost by writing new hold node\n", ret, readlen);
  434                         goto fill;
  435                 }
  436                 if (ri.nodetype != JFFS2_NODETYPE_INODE) {
  437                         printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had node type 0x%04x instead of JFFS2_NODETYPE_INODE(0x%04x)\n",
  438                                fn->raw->flash_offset & ~3, ri.nodetype, JFFS2_NODETYPE_INODE);
  439                         return -EIO;
  440                 }
  441                 if (ri.totlen != sizeof(ri)) {
  442                         printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had totlen 0x%x instead of expected 0x%x\n",
  443                                fn->raw->flash_offset & ~3, ri.totlen, sizeof(ri));
  444                         return -EIO;
  445                 }
  446                 crc = crc32(0, &ri, sizeof(ri)-8);
  447                 if (crc != ri.node_crc) {
  448                         printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had CRC 0x%08x which doesn't match calculated CRC 0x%08x\n",
  449                                fn->raw->flash_offset & ~3, ri.node_crc, crc);
  450                         /* FIXME: We could possibly deal with this by writing new holes for each frag */
  451                         printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%lu will be lost\n", 
  452                                start, end, inode->i_ino);
  453                         goto fill;
  454                 }
  455                 if (ri.compr != JFFS2_COMPR_ZERO) {
  456                         printk(KERN_WARNING "jffs2_garbage_collect_hole: Node 0x%08x wasn't a hole node!\n", fn->raw->flash_offset & ~3);
  457                         printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%lu will be lost\n", 
  458                                start, end, inode->i_ino);
  459                         goto fill;
  460                 }
  461         } else {
  462         fill:
  463                 ri.magic = JFFS2_MAGIC_BITMASK;
  464                 ri.nodetype = JFFS2_NODETYPE_INODE;
  465                 ri.totlen = sizeof(ri);
  466                 ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4);
  467 
  468                 ri.ino = inode->i_ino;
  469                 ri.version = ++f->highest_version;
  470                 ri.offset = start;
  471                 ri.dsize = end - start;
  472                 ri.csize = 0;
  473                 ri.compr = JFFS2_COMPR_ZERO;
  474         }
  475         ri.mode = inode->i_mode;
  476         ri.uid = inode->i_uid;
  477         ri.gid = inode->i_gid;
  478         ri.isize = inode->i_size;
  479         ri.atime = inode->i_atime;
  480         ri.ctime = inode->i_ctime;
  481         ri.mtime = inode->i_mtime;
  482         ri.data_crc = 0;
  483         ri.node_crc = crc32(0, &ri, sizeof(ri)-8);
  484 
  485         ret = jffs2_reserve_space_gc(c, sizeof(ri), &phys_ofs, &alloclen);
  486         if (ret) {
  487                 printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_hole failed: %d\n",
  488                        sizeof(ri), ret);
  489                 return ret;
  490         }
  491         new_fn = jffs2_write_dnode(inode, &ri, NULL, 0, phys_ofs, NULL);
  492 
  493         if (IS_ERR(new_fn)) {
  494                 printk(KERN_WARNING "Error writing new hole node: %ld\n", PTR_ERR(new_fn));
  495                 return PTR_ERR(new_fn);
  496         }
  497         if (ri.version == f->highest_version) {
  498                 jffs2_add_full_dnode_to_inode(c, f, new_fn);
  499                 if (f->metadata) {
  500                         jffs2_mark_node_obsolete(c, f->metadata->raw);
  501                         jffs2_free_full_dnode(f->metadata);
  502                         f->metadata = NULL;
  503                 }
  504                 return 0;
  505         }
  506 
  507         /* 
  508          * We should only get here in the case where the node we are
  509          * replacing had more than one frag, so we kept the same version
  510          * number as before. (Except in case of error -- see 'goto fill;' 
  511          * above.)
  512          */
  513         D1(if(fn->frags <= 1) {
  514                 printk(KERN_WARNING "jffs2_garbage_collect_hole: Replacing fn with %d frag(s) but new ver %d != highest_version %d of ino #%d\n",
  515                        fn->frags, ri.version, f->highest_version, ri.ino);
  516         });
  517 
  518         for (frag = f->fraglist; frag; frag = frag->next) {
  519                 if (frag->ofs > fn->size + fn->ofs)
  520                         break;
  521                 if (frag->node == fn) {
  522                         frag->node = new_fn;
  523                         new_fn->frags++;
  524                         fn->frags--;
  525                 }
  526         }
  527         if (fn->frags) {
  528                 printk(KERN_WARNING "jffs2_garbage_collect_hole: Old node still has frags!\n");
  529                 BUG();
  530         }
  531         if (!new_fn->frags) {
  532                 printk(KERN_WARNING "jffs2_garbage_collect_hole: New node has no frags!\n");
  533                 BUG();
  534         }
  535                 
  536         jffs2_mark_node_obsolete(c, fn->raw);
  537         jffs2_free_full_dnode(fn);
  538         
  539         return 0;
  540 }
  541 
  542 static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
  543                                        struct inode *inode, struct jffs2_full_dnode *fn,
  544                                        __u32 start, __u32 end)
  545 {
  546         struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
  547         struct jffs2_full_dnode *new_fn;
  548         struct jffs2_raw_inode ri;
  549         __u32 alloclen, phys_ofs, offset, orig_end;     
  550         int ret = 0;
  551         unsigned char *comprbuf = NULL, *writebuf;
  552         struct page *pg;
  553         unsigned char *pg_ptr;
  554 
  555 
  556         memset(&ri, 0, sizeof(ri));
  557 
  558         D1(printk(KERN_DEBUG "Writing replacement dnode for ino #%lu from offset 0x%x to 0x%x\n",
  559                   inode->i_ino, start, end));
  560 
  561         orig_end = end;
  562 
  563 
  564         /* If we're looking at the last node in the block we're
  565            garbage-collecting, we allow ourselves to merge as if the
  566            block was already erasing. We're likely to be GC'ing a
  567            partial page, and the next block we GC is likely to have
  568            the other half of this page right at the beginning, which
  569            means we'd expand it _then_, as nr_erasing_blocks would have
  570            increased since we checked, and in doing so would obsolete 
  571            the partial node which we'd have written here. Meaning that 
  572            the GC would churn and churn, and just leave dirty blocks in
  573            it's wake.
  574         */
  575         if(c->nr_free_blocks + c->nr_erasing_blocks > JFFS2_RESERVED_BLOCKS_GCMERGE - (fn->raw->next_phys?0:1)) {
  576                 /* Shitloads of space */
  577                 /* FIXME: Integrate this properly with GC calculations */
  578                 start &= ~(PAGE_CACHE_SIZE-1);
  579                 end = min_t(__u32, start + PAGE_CACHE_SIZE, inode->i_size);
  580                 D1(printk(KERN_DEBUG "Plenty of free space, so expanding to write from offset 0x%x to 0x%x\n",
  581                           start, end));
  582                 if (end < orig_end) {
  583                         printk(KERN_WARNING "Eep. jffs2_garbage_collect_dnode extended node to write, but it got smaller: start 0x%x, orig_end 0x%x, end 0x%x\n", start, orig_end, end);
  584                         end = orig_end;
  585                 }
  586         }
  587         
  588         /* First, use readpage() to read the appropriate page into the page cache */
  589         /* Q: What happens if we actually try to GC the _same_ page for which commit_write()
  590          *    triggered garbage collection in the first place?
  591          * A: I _think_ it's OK. read_cache_page shouldn't deadlock, we'll write out the
  592          *    page OK. We'll actually write it out again in commit_write, which is a little
  593          *    suboptimal, but at least we're correct.
  594          */
  595         pg = read_cache_page(inode->i_mapping, start >> PAGE_CACHE_SHIFT, (void *)jffs2_do_readpage_unlock, inode);
  596 
  597         if (IS_ERR(pg)) {
  598                 printk(KERN_WARNING "read_cache_page() returned error: %ld\n", PTR_ERR(pg));
  599                 return PTR_ERR(pg);
  600         }
  601         pg_ptr = (char *)kmap(pg);
  602         comprbuf = kmalloc(end - start, GFP_KERNEL);
  603 
  604         offset = start;
  605         while(offset < orig_end) {
  606                 __u32 datalen;
  607                 __u32 cdatalen;
  608                 char comprtype = JFFS2_COMPR_NONE;
  609 
  610                 ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen);
  611 
  612                 if (ret) {
  613                         printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_dnode failed: %d\n",
  614                                sizeof(ri)+ JFFS2_MIN_DATA_LEN, ret);
  615                         break;
  616                 }
  617                 cdatalen = min(alloclen - sizeof(ri), end - offset);
  618                 datalen = end - offset;
  619 
  620                 writebuf = pg_ptr + (offset & (PAGE_CACHE_SIZE -1));
  621 
  622                 if (comprbuf) {
  623                         comprtype = jffs2_compress(writebuf, comprbuf, &datalen, &cdatalen);
  624                 }
  625                 if (comprtype) {
  626                         writebuf = comprbuf;
  627                 } else {
  628                         datalen = cdatalen;
  629                 }
  630                 ri.magic = JFFS2_MAGIC_BITMASK;
  631                 ri.nodetype = JFFS2_NODETYPE_INODE;
  632                 ri.totlen = sizeof(ri) + cdatalen;
  633                 ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4);
  634 
  635                 ri.ino = inode->i_ino;
  636                 ri.version = ++f->highest_version;
  637                 ri.mode = inode->i_mode;
  638                 ri.uid = inode->i_uid;
  639                 ri.gid = inode->i_gid;
  640                 ri.isize = inode->i_size;
  641                 ri.atime = inode->i_atime;
  642                 ri.ctime = inode->i_ctime;
  643                 ri.mtime = inode->i_mtime;
  644                 ri.offset = offset;
  645                 ri.csize = cdatalen;
  646                 ri.dsize = datalen;
  647                 ri.compr = comprtype;
  648                 ri.node_crc = crc32(0, &ri, sizeof(ri)-8);
  649                 ri.data_crc = crc32(0, writebuf, cdatalen);
  650         
  651                 new_fn = jffs2_write_dnode(inode, &ri, writebuf, cdatalen, phys_ofs, NULL);
  652 
  653                 if (IS_ERR(new_fn)) {
  654                         printk(KERN_WARNING "Error writing new dnode: %ld\n", PTR_ERR(new_fn));
  655                         ret = PTR_ERR(new_fn);
  656                         break;
  657                 }
  658                 ret = jffs2_add_full_dnode_to_inode(c, f, new_fn);
  659                 offset += datalen;
  660                 if (f->metadata) {
  661                         jffs2_mark_node_obsolete(c, f->metadata->raw);
  662                         jffs2_free_full_dnode(f->metadata);
  663                         f->metadata = NULL;
  664                 }
  665         }
  666         if (comprbuf) kfree(comprbuf);
  667 
  668         kunmap(pg);
  669         /* XXX: Does the page get freed automatically? */
  670         /* AAA: Judging by the unmount getting stuck in __wait_on_page, nope. */
  671         page_cache_release(pg);
  672         return ret;
  673 }
  674 

Cache object: c724827d8337052ae65b62aa08fbab73


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