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/write.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: write.c,v 1.30.2.1 2002/08/08 08:36:31 dwmw2 Exp $
   35  *
   36  */
   37 
   38 #include <linux/kernel.h>
   39 #include <linux/fs.h>
   40 #include <linux/jffs2.h>
   41 #include <linux/mtd/mtd.h>
   42 #include "nodelist.h"
   43 #include <linux/crc32.h>
   44 
   45 /* jffs2_new_inode: allocate a new inode and inocache, add it to the hash,
   46    fill in the raw_inode while you're at it. */
   47 struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri)
   48 {
   49         struct inode *inode;
   50         struct super_block *sb = dir_i->i_sb;
   51         struct jffs2_inode_cache *ic;
   52         struct jffs2_sb_info *c;
   53         struct jffs2_inode_info *f;
   54 
   55         D1(printk(KERN_DEBUG "jffs2_new_inode(): dir_i %ld, mode 0x%x\n", dir_i->i_ino, mode));
   56 
   57         c = JFFS2_SB_INFO(sb);
   58         memset(ri, 0, sizeof(*ri));
   59 
   60         ic = jffs2_alloc_inode_cache();
   61         if (!ic) {
   62                 return ERR_PTR(-ENOMEM);
   63         }
   64         memset(ic, 0, sizeof(*ic));
   65         
   66         inode = new_inode(sb);
   67         
   68         if (!inode) {
   69                 jffs2_free_inode_cache(ic);
   70                 return ERR_PTR(-ENOMEM);
   71         }
   72 
   73         /* Alloc jffs2_inode_info when that's split in 2.5 */
   74 
   75         f = JFFS2_INODE_INFO(inode);
   76         memset(f, 0, sizeof(*f));
   77         init_MUTEX_LOCKED(&f->sem);
   78         f->inocache = ic;
   79         inode->i_nlink = f->inocache->nlink = 1;
   80         f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
   81         f->inocache->ino = ri->ino = inode->i_ino = ++c->highest_ino;
   82         D1(printk(KERN_DEBUG "jffs2_new_inode(): Assigned ino# %d\n", ri->ino));
   83         jffs2_add_ino_cache(c, f->inocache);
   84 
   85         ri->magic = JFFS2_MAGIC_BITMASK;
   86         ri->nodetype = JFFS2_NODETYPE_INODE;
   87         ri->totlen = PAD(sizeof(*ri));
   88         ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4);
   89         ri->mode = mode;
   90         f->highest_version = ri->version = 1;
   91         ri->uid = current->fsuid;
   92         if (dir_i->i_mode & S_ISGID) {
   93                 ri->gid = dir_i->i_gid;
   94                 if (S_ISDIR(mode))
   95                         ri->mode |= S_ISGID;
   96         } else {
   97                 ri->gid = current->fsgid;
   98         }
   99         inode->i_mode = ri->mode;
  100         inode->i_gid = ri->gid;
  101         inode->i_uid = ri->uid;
  102         inode->i_atime = inode->i_ctime = inode->i_mtime = 
  103                 ri->atime = ri->mtime = ri->ctime = CURRENT_TIME;
  104         inode->i_blksize = PAGE_SIZE;
  105         inode->i_blocks = 0;
  106         inode->i_size = 0;
  107 
  108         insert_inode_hash(inode);
  109 
  110         return inode;
  111 }
  112 
  113 /* This ought to be in core MTD code. All registered MTD devices
  114    without writev should have this put in place. Bug the MTD
  115    maintainer */
  116 static int mtd_fake_writev(struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen)
  117 {
  118         unsigned long i;
  119         size_t totlen = 0, thislen;
  120         int ret = 0;
  121 
  122         for (i=0; i<count; i++) {
  123                 ret = mtd->write(mtd, to, vecs[i].iov_len, &thislen, vecs[i].iov_base);
  124                 totlen += thislen;
  125                 if (ret || thislen != vecs[i].iov_len)
  126                         break;
  127                 to += vecs[i].iov_len;
  128         }
  129         if (retlen)
  130                 *retlen = totlen;
  131         return ret;
  132 }
  133 
  134 
  135 static inline int mtd_writev(struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen)
  136 {
  137         if (mtd->writev)
  138                 return mtd->writev(mtd,vecs,count,to,retlen);
  139         else
  140                 return mtd_fake_writev(mtd, vecs, count, to, retlen);
  141 }
  142 
  143 static void writecheck(struct mtd_info *mtd, __u32 ofs)
  144 {
  145         unsigned char buf[16];
  146         ssize_t retlen;
  147         int ret, i;
  148 
  149         ret = mtd->read(mtd, ofs, 16, &retlen, buf);
  150         if (ret && retlen != 16) {
  151                 D1(printk(KERN_DEBUG "read failed or short in writecheck(). ret %d, retlen %d\n", ret, retlen));
  152                 return;
  153         }
  154         ret = 0;
  155         for (i=0; i<16; i++) {
  156                 if (buf[i] != 0xff)
  157                         ret = 1;
  158         }
  159         if (ret) {
  160                 printk(KERN_WARNING "ARGH. About to write node to 0x%08x on flash, but there's data already there:\n", ofs);
  161                 printk(KERN_WARNING "0x%08x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", 
  162                        ofs,
  163                        buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7],
  164                        buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
  165         }
  166 }
  167 
  168         
  169         
  170 
  171 /* jffs2_write_dnode - given a raw_inode, allocate a full_dnode for it, 
  172    write it to the flash, link it into the existing inode/fragment list */
  173 
  174 struct jffs2_full_dnode *jffs2_write_dnode(struct inode *inode, struct jffs2_raw_inode *ri, const unsigned char *data, __u32 datalen, __u32 flash_ofs,  __u32 *writelen)
  175 
  176 {
  177         struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
  178         struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
  179         struct jffs2_raw_node_ref *raw;
  180         struct jffs2_full_dnode *fn;
  181         ssize_t retlen;
  182         struct iovec vecs[2];
  183         int ret;
  184 
  185         D1(if(ri->hdr_crc != crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)) {
  186                 printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dnode()\n");
  187                 BUG();
  188         }
  189            );
  190         vecs[0].iov_base = ri;
  191         vecs[0].iov_len = sizeof(*ri);
  192         vecs[1].iov_base = (unsigned char *)data;
  193         vecs[1].iov_len = datalen;
  194 
  195         writecheck(c->mtd, flash_ofs);
  196 
  197         if (ri->totlen != sizeof(*ri) + datalen) {
  198                 printk(KERN_WARNING "jffs2_write_dnode: ri->totlen (0x%08x) != sizeof(*ri) (0x%08x) + datalen (0x%08x)\n", ri->totlen, sizeof(*ri), datalen);
  199         }
  200         raw = jffs2_alloc_raw_node_ref();
  201         if (!raw)
  202                 return ERR_PTR(-ENOMEM);
  203         
  204         fn = jffs2_alloc_full_dnode();
  205         if (!fn) {
  206                 jffs2_free_raw_node_ref(raw);
  207                 return ERR_PTR(-ENOMEM);
  208         }
  209         raw->flash_offset = flash_ofs;
  210         raw->totlen = PAD(ri->totlen);
  211         raw->next_phys = NULL;
  212 
  213         fn->ofs = ri->offset;
  214         fn->size = ri->dsize;
  215         fn->frags = 0;
  216         fn->raw = raw;
  217 
  218         ret = mtd_writev(c->mtd, vecs, 2, flash_ofs, &retlen);
  219         if (ret || (retlen != sizeof(*ri) + datalen)) {
  220                 printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %d\n", 
  221                        sizeof(*ri)+datalen, flash_ofs, ret, retlen);
  222                 /* Mark the space as dirtied */
  223                 if (retlen) {
  224                         /* Doesn't belong to any inode */
  225                         raw->next_in_ino = NULL;
  226 
  227                         /* Don't change raw->size to match retlen. We may have 
  228                            written the node header already, and only the data will
  229                            seem corrupted, in which case the scan would skip over
  230                            any node we write before the original intended end of 
  231                            this node */
  232                         jffs2_add_physical_node_ref(c, raw, sizeof(*ri)+datalen, 1);
  233                         jffs2_mark_node_obsolete(c, raw);
  234                 } else {
  235                         printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset);
  236                         jffs2_free_raw_node_ref(raw);
  237                 }
  238 
  239                 /* Release the full_dnode which is now useless, and return */
  240                 jffs2_free_full_dnode(fn);
  241                 if (writelen)
  242                         *writelen = retlen;
  243                 return ERR_PTR(ret?ret:-EIO);
  244         }
  245         /* Mark the space used */
  246         jffs2_add_physical_node_ref(c, raw, retlen, 0);
  247 
  248         /* Link into per-inode list */
  249         raw->next_in_ino = f->inocache->nodes;
  250         f->inocache->nodes = raw;
  251 
  252         D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n", flash_ofs, ri->dsize, ri->csize, ri->node_crc, ri->data_crc, ri->totlen));
  253         if (writelen)
  254                 *writelen = retlen;
  255 
  256         f->inocache->nodes = raw;
  257         return fn;
  258 }
  259 
  260 struct jffs2_full_dirent *jffs2_write_dirent(struct inode *inode, struct jffs2_raw_dirent *rd, const unsigned char *name, __u32 namelen, __u32 flash_ofs,  __u32 *writelen)
  261 {
  262         struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
  263         struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
  264         struct jffs2_raw_node_ref *raw;
  265         struct jffs2_full_dirent *fd;
  266         ssize_t retlen;
  267         struct iovec vecs[2];
  268         int ret;
  269 
  270         D1(printk(KERN_DEBUG "jffs2_write_dirent(ino #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x)\n", rd->pino, name, name, rd->ino, rd->name_crc));
  271         writecheck(c->mtd, flash_ofs);
  272 
  273         D1(if(rd->hdr_crc != crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)) {
  274                 printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dirent()\n");
  275                 BUG();
  276         }
  277            );
  278 
  279         vecs[0].iov_base = rd;
  280         vecs[0].iov_len = sizeof(*rd);
  281         vecs[1].iov_base = (unsigned char *)name;
  282         vecs[1].iov_len = namelen;
  283         
  284         raw = jffs2_alloc_raw_node_ref();
  285 
  286         if (!raw)
  287                 return ERR_PTR(-ENOMEM);
  288 
  289         fd = jffs2_alloc_full_dirent(namelen+1);
  290         if (!fd) {
  291                 jffs2_free_raw_node_ref(raw);
  292                 return ERR_PTR(-ENOMEM);
  293         }
  294         raw->flash_offset = flash_ofs;
  295         raw->totlen = PAD(rd->totlen);
  296         raw->next_in_ino = f->inocache->nodes;
  297         f->inocache->nodes = raw;
  298         raw->next_phys = NULL;
  299 
  300         fd->version = rd->version;
  301         fd->ino = rd->ino;
  302         fd->nhash = full_name_hash(name, strlen(name));
  303         fd->type = rd->type;
  304         memcpy(fd->name, name, namelen);
  305         fd->name[namelen]=0;
  306         fd->raw = raw;
  307 
  308         ret = mtd_writev(c->mtd, vecs, 2, flash_ofs, &retlen);
  309                 if (ret || (retlen != sizeof(*rd) + namelen)) {
  310                         printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %d\n", 
  311                                sizeof(*rd)+namelen, flash_ofs, ret, retlen);
  312                 /* Mark the space as dirtied */
  313                         if (retlen) {
  314                                 jffs2_add_physical_node_ref(c, raw, sizeof(*rd)+namelen, 1);
  315                                 jffs2_mark_node_obsolete(c, raw);
  316                         } else {
  317                                 printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset);
  318                                 jffs2_free_raw_node_ref(raw);
  319                         }
  320 
  321                 /* Release the full_dnode which is now useless, and return */
  322                 jffs2_free_full_dirent(fd);
  323                 if (writelen)
  324                         *writelen = retlen;
  325                 return ERR_PTR(ret?ret:-EIO);
  326         }
  327         /* Mark the space used */
  328         jffs2_add_physical_node_ref(c, raw, retlen, 0);
  329         if (writelen)
  330                 *writelen = retlen;
  331 
  332         f->inocache->nodes = raw;
  333         return fd;
  334 }

Cache object: 9ae7b22eb2fedd677c6f236b9cabbce6


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