linux/fs/jffs2/summary.c
<<
>>
Prefs
   1/*
   2 * JFFS2 -- Journalling Flash File System, Version 2.
   3 *
   4 * Copyright © 2004  Ferenc Havasi <havasi@inf.u-szeged.hu>,
   5 *                   Zoltan Sogor <weth@inf.u-szeged.hu>,
   6 *                   Patrik Kluba <pajko@halom.u-szeged.hu>,
   7 *                   University of Szeged, Hungary
   8 *             2006  KaiGai Kohei <kaigai@ak.jp.nec.com>
   9 *
  10 * For licensing information, see the file 'LICENCE' in this directory.
  11 *
  12 */
  13
  14#include <linux/kernel.h>
  15#include <linux/slab.h>
  16#include <linux/mtd/mtd.h>
  17#include <linux/pagemap.h>
  18#include <linux/crc32.h>
  19#include <linux/compiler.h>
  20#include <linux/vmalloc.h>
  21#include "nodelist.h"
  22#include "debug.h"
  23
  24int jffs2_sum_init(struct jffs2_sb_info *c)
  25{
  26        uint32_t sum_size = max_t(uint32_t, c->sector_size, MAX_SUMMARY_SIZE);
  27
  28        c->summary = kzalloc(sizeof(struct jffs2_summary), GFP_KERNEL);
  29
  30        if (!c->summary) {
  31                JFFS2_WARNING("Can't allocate memory for summary information!\n");
  32                return -ENOMEM;
  33        }
  34
  35        c->summary->sum_buf = kmalloc(sum_size, GFP_KERNEL);
  36
  37        if (!c->summary->sum_buf) {
  38                JFFS2_WARNING("Can't allocate buffer for writing out summary information!\n");
  39                kfree(c->summary);
  40                return -ENOMEM;
  41        }
  42
  43        dbg_summary("returned successfully\n");
  44
  45        return 0;
  46}
  47
  48void jffs2_sum_exit(struct jffs2_sb_info *c)
  49{
  50        dbg_summary("called\n");
  51
  52        jffs2_sum_disable_collecting(c->summary);
  53
  54        kfree(c->summary->sum_buf);
  55        c->summary->sum_buf = NULL;
  56
  57        kfree(c->summary);
  58        c->summary = NULL;
  59}
  60
  61static int jffs2_sum_add_mem(struct jffs2_summary *s, union jffs2_sum_mem *item)
  62{
  63        if (!s->sum_list_head)
  64                s->sum_list_head = (union jffs2_sum_mem *) item;
  65        if (s->sum_list_tail)
  66                s->sum_list_tail->u.next = (union jffs2_sum_mem *) item;
  67        s->sum_list_tail = (union jffs2_sum_mem *) item;
  68
  69        switch (je16_to_cpu(item->u.nodetype)) {
  70                case JFFS2_NODETYPE_INODE:
  71                        s->sum_size += JFFS2_SUMMARY_INODE_SIZE;
  72                        s->sum_num++;
  73                        dbg_summary("inode (%u) added to summary\n",
  74                                                je32_to_cpu(item->i.inode));
  75                        break;
  76                case JFFS2_NODETYPE_DIRENT:
  77                        s->sum_size += JFFS2_SUMMARY_DIRENT_SIZE(item->d.nsize);
  78                        s->sum_num++;
  79                        dbg_summary("dirent (%u) added to summary\n",
  80                                                je32_to_cpu(item->d.ino));
  81                        break;
  82#ifdef CONFIG_JFFS2_FS_XATTR
  83                case JFFS2_NODETYPE_XATTR:
  84                        s->sum_size += JFFS2_SUMMARY_XATTR_SIZE;
  85                        s->sum_num++;
  86                        dbg_summary("xattr (xid=%u, version=%u) added to summary\n",
  87                                    je32_to_cpu(item->x.xid), je32_to_cpu(item->x.version));
  88                        break;
  89                case JFFS2_NODETYPE_XREF:
  90                        s->sum_size += JFFS2_SUMMARY_XREF_SIZE;
  91                        s->sum_num++;
  92                        dbg_summary("xref added to summary\n");
  93                        break;
  94#endif
  95                default:
  96                        JFFS2_WARNING("UNKNOWN node type %u\n",
  97                                            je16_to_cpu(item->u.nodetype));
  98                        return 1;
  99        }
 100        return 0;
 101}
 102
 103
 104/* The following 3 functions are called from scan.c to collect summary info for not closed jeb */
 105
 106int jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size)
 107{
 108        dbg_summary("called with %u\n", size);
 109        s->sum_padded += size;
 110        return 0;
 111}
 112
 113int jffs2_sum_add_inode_mem(struct jffs2_summary *s, struct jffs2_raw_inode *ri,
 114                                uint32_t ofs)
 115{
 116        struct jffs2_sum_inode_mem *temp = kmalloc(sizeof(struct jffs2_sum_inode_mem), GFP_KERNEL);
 117
 118        if (!temp)
 119                return -ENOMEM;
 120
 121        temp->nodetype = ri->nodetype;
 122        temp->inode = ri->ino;
 123        temp->version = ri->version;
 124        temp->offset = cpu_to_je32(ofs); /* relative offset from the begining of the jeb */
 125        temp->totlen = ri->totlen;
 126        temp->next = NULL;
 127
 128        return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
 129}
 130
 131int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *rd,
 132                                uint32_t ofs)
 133{
 134        struct jffs2_sum_dirent_mem *temp =
 135                kmalloc(sizeof(struct jffs2_sum_dirent_mem) + rd->nsize, GFP_KERNEL);
 136
 137        if (!temp)
 138                return -ENOMEM;
 139
 140        temp->nodetype = rd->nodetype;
 141        temp->totlen = rd->totlen;
 142        temp->offset = cpu_to_je32(ofs);        /* relative from the begining of the jeb */
 143        temp->pino = rd->pino;
 144        temp->version = rd->version;
 145        temp->ino = rd->ino;
 146        temp->nsize = rd->nsize;
 147        temp->type = rd->type;
 148        temp->next = NULL;
 149
 150        memcpy(temp->name, rd->name, rd->nsize);
 151
 152        return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
 153}
 154
 155#ifdef CONFIG_JFFS2_FS_XATTR
 156int jffs2_sum_add_xattr_mem(struct jffs2_summary *s, struct jffs2_raw_xattr *rx, uint32_t ofs)
 157{
 158        struct jffs2_sum_xattr_mem *temp;
 159
 160        temp = kmalloc(sizeof(struct jffs2_sum_xattr_mem), GFP_KERNEL);
 161        if (!temp)
 162                return -ENOMEM;
 163
 164        temp->nodetype = rx->nodetype;
 165        temp->xid = rx->xid;
 166        temp->version = rx->version;
 167        temp->offset = cpu_to_je32(ofs);
 168        temp->totlen = rx->totlen;
 169        temp->next = NULL;
 170
 171        return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
 172}
 173
 174int jffs2_sum_add_xref_mem(struct jffs2_summary *s, struct jffs2_raw_xref *rr, uint32_t ofs)
 175{
 176        struct jffs2_sum_xref_mem *temp;
 177
 178        temp = kmalloc(sizeof(struct jffs2_sum_xref_mem), GFP_KERNEL);
 179        if (!temp)
 180                return -ENOMEM;
 181
 182        temp->nodetype = rr->nodetype;
 183        temp->offset = cpu_to_je32(ofs);
 184        temp->next = NULL;
 185
 186        return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
 187}
 188#endif
 189/* Cleanup every collected summary information */
 190
 191static void jffs2_sum_clean_collected(struct jffs2_summary *s)
 192{
 193        union jffs2_sum_mem *temp;
 194
 195        if (!s->sum_list_head) {
 196                dbg_summary("already empty\n");
 197        }
 198        while (s->sum_list_head) {
 199                temp = s->sum_list_head;
 200                s->sum_list_head = s->sum_list_head->u.next;
 201                kfree(temp);
 202        }
 203        s->sum_list_tail = NULL;
 204        s->sum_padded = 0;
 205        s->sum_num = 0;
 206}
 207
 208void jffs2_sum_reset_collected(struct jffs2_summary *s)
 209{
 210        dbg_summary("called\n");
 211        jffs2_sum_clean_collected(s);
 212        s->sum_size = 0;
 213}
 214
 215void jffs2_sum_disable_collecting(struct jffs2_summary *s)
 216{
 217        dbg_summary("called\n");
 218        jffs2_sum_clean_collected(s);
 219        s->sum_size = JFFS2_SUMMARY_NOSUM_SIZE;
 220}
 221
 222int jffs2_sum_is_disabled(struct jffs2_summary *s)
 223{
 224        return (s->sum_size == JFFS2_SUMMARY_NOSUM_SIZE);
 225}
 226
 227/* Move the collected summary information into sb (called from scan.c) */
 228
 229void jffs2_sum_move_collected(struct jffs2_sb_info *c, struct jffs2_summary *s)
 230{
 231        dbg_summary("oldsize=0x%x oldnum=%u => newsize=0x%x newnum=%u\n",
 232                                c->summary->sum_size, c->summary->sum_num,
 233                                s->sum_size, s->sum_num);
 234
 235        c->summary->sum_size = s->sum_size;
 236        c->summary->sum_num = s->sum_num;
 237        c->summary->sum_padded = s->sum_padded;
 238        c->summary->sum_list_head = s->sum_list_head;
 239        c->summary->sum_list_tail = s->sum_list_tail;
 240
 241        s->sum_list_head = s->sum_list_tail = NULL;
 242}
 243
 244/* Called from wbuf.c to collect writed node info */
 245
 246int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs,
 247                                unsigned long count, uint32_t ofs)
 248{
 249        union jffs2_node_union *node;
 250        struct jffs2_eraseblock *jeb;
 251
 252        if (c->summary->sum_size == JFFS2_SUMMARY_NOSUM_SIZE) {
 253                dbg_summary("Summary is disabled for this jeb! Skipping summary info!\n");
 254                return 0;
 255        }
 256
 257        node = invecs[0].iov_base;
 258        jeb = &c->blocks[ofs / c->sector_size];
 259        ofs -= jeb->offset;
 260
 261        switch (je16_to_cpu(node->u.nodetype)) {
 262                case JFFS2_NODETYPE_INODE: {
 263                        struct jffs2_sum_inode_mem *temp =
 264                                kmalloc(sizeof(struct jffs2_sum_inode_mem), GFP_KERNEL);
 265
 266                        if (!temp)
 267                                goto no_mem;
 268
 269                        temp->nodetype = node->i.nodetype;
 270                        temp->inode = node->i.ino;
 271                        temp->version = node->i.version;
 272                        temp->offset = cpu_to_je32(ofs);
 273                        temp->totlen = node->i.totlen;
 274                        temp->next = NULL;
 275
 276                        return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
 277                }
 278
 279                case JFFS2_NODETYPE_DIRENT: {
 280                        struct jffs2_sum_dirent_mem *temp =
 281                                kmalloc(sizeof(struct jffs2_sum_dirent_mem) + node->d.nsize, GFP_KERNEL);
 282
 283                        if (!temp)
 284                                goto no_mem;
 285
 286                        temp->nodetype = node->d.nodetype;
 287                        temp->totlen = node->d.totlen;
 288                        temp->offset = cpu_to_je32(ofs);
 289                        temp->pino = node->d.pino;
 290                        temp->version = node->d.version;
 291                        temp->ino = node->d.ino;
 292                        temp->nsize = node->d.nsize;
 293                        temp->type = node->d.type;
 294                        temp->next = NULL;
 295
 296                        switch (count) {
 297                                case 1:
 298                                        memcpy(temp->name,node->d.name,node->d.nsize);
 299                                        break;
 300
 301                                case 2:
 302                                        memcpy(temp->name,invecs[1].iov_base,node->d.nsize);
 303                                        break;
 304
 305                                default:
 306                                        BUG();  /* impossible count value */
 307                                        break;
 308                        }
 309
 310                        return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
 311                }
 312#ifdef CONFIG_JFFS2_FS_XATTR
 313                case JFFS2_NODETYPE_XATTR: {
 314                        struct jffs2_sum_xattr_mem *temp;
 315                        temp = kmalloc(sizeof(struct jffs2_sum_xattr_mem), GFP_KERNEL);
 316                        if (!temp)
 317                                goto no_mem;
 318
 319                        temp->nodetype = node->x.nodetype;
 320                        temp->xid = node->x.xid;
 321                        temp->version = node->x.version;
 322                        temp->totlen = node->x.totlen;
 323                        temp->offset = cpu_to_je32(ofs);
 324                        temp->next = NULL;
 325
 326                        return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
 327                }
 328                case JFFS2_NODETYPE_XREF: {
 329                        struct jffs2_sum_xref_mem *temp;
 330                        temp = kmalloc(sizeof(struct jffs2_sum_xref_mem), GFP_KERNEL);
 331                        if (!temp)
 332                                goto no_mem;
 333                        temp->nodetype = node->r.nodetype;
 334                        temp->offset = cpu_to_je32(ofs);
 335                        temp->next = NULL;
 336
 337                        return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
 338                }
 339#endif
 340                case JFFS2_NODETYPE_PADDING:
 341                        dbg_summary("node PADDING\n");
 342                        c->summary->sum_padded += je32_to_cpu(node->u.totlen);
 343                        break;
 344
 345                case JFFS2_NODETYPE_CLEANMARKER:
 346                        dbg_summary("node CLEANMARKER\n");
 347                        break;
 348
 349                case JFFS2_NODETYPE_SUMMARY:
 350                        dbg_summary("node SUMMARY\n");
 351                        break;
 352
 353                default:
 354                        /* If you implement a new node type you should also implement
 355                           summary support for it or disable summary.
 356                        */
 357                        BUG();
 358                        break;
 359        }
 360
 361        return 0;
 362
 363no_mem:
 364        JFFS2_WARNING("MEMORY ALLOCATION ERROR!");
 365        return -ENOMEM;
 366}
 367
 368static struct jffs2_raw_node_ref *sum_link_node_ref(struct jffs2_sb_info *c,
 369                                                    struct jffs2_eraseblock *jeb,
 370                                                    uint32_t ofs, uint32_t len,
 371                                                    struct jffs2_inode_cache *ic)
 372{
 373        /* If there was a gap, mark it dirty */
 374        if ((ofs & ~3) > c->sector_size - jeb->free_size) {
 375                /* Ew. Summary doesn't actually tell us explicitly about dirty space */
 376                jffs2_scan_dirty_space(c, jeb, (ofs & ~3) - (c->sector_size - jeb->free_size));
 377        }
 378
 379        return jffs2_link_node_ref(c, jeb, jeb->offset + ofs, len, ic);
 380}
 381
 382/* Process the stored summary information - helper function for jffs2_sum_scan_sumnode() */
 383
 384static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
 385                                struct jffs2_raw_summary *summary, uint32_t *pseudo_random)
 386{
 387        struct jffs2_inode_cache *ic;
 388        struct jffs2_full_dirent *fd;
 389        void *sp;
 390        int i, ino;
 391        int err;
 392
 393        sp = summary->sum;
 394
 395        for (i=0; i<je32_to_cpu(summary->sum_num); i++) {
 396                dbg_summary("processing summary index %d\n", i);
 397
 398                cond_resched();
 399
 400                /* Make sure there's a spare ref for dirty space */
 401                err = jffs2_prealloc_raw_node_refs(c, jeb, 2);
 402                if (err)
 403                        return err;
 404
 405                switch (je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) {
 406                        case JFFS2_NODETYPE_INODE: {
 407                                struct jffs2_sum_inode_flash *spi;
 408                                spi = sp;
 409
 410                                ino = je32_to_cpu(spi->inode);
 411
 412                                dbg_summary("Inode at 0x%08x-0x%08x\n",
 413                                            jeb->offset + je32_to_cpu(spi->offset),
 414                                            jeb->offset + je32_to_cpu(spi->offset) + je32_to_cpu(spi->totlen));
 415
 416                                ic = jffs2_scan_make_ino_cache(c, ino);
 417                                if (!ic) {
 418                                        JFFS2_NOTICE("scan_make_ino_cache failed\n");
 419                                        return -ENOMEM;
 420                                }
 421
 422                                sum_link_node_ref(c, jeb, je32_to_cpu(spi->offset) | REF_UNCHECKED,
 423                                                  PAD(je32_to_cpu(spi->totlen)), ic);
 424
 425                                *pseudo_random += je32_to_cpu(spi->version);
 426
 427                                sp += JFFS2_SUMMARY_INODE_SIZE;
 428
 429                                break;
 430                        }
 431
 432                        case JFFS2_NODETYPE_DIRENT: {
 433                                struct jffs2_sum_dirent_flash *spd;
 434                                int checkedlen;
 435                                spd = sp;
 436
 437                                dbg_summary("Dirent at 0x%08x-0x%08x\n",
 438                                            jeb->offset + je32_to_cpu(spd->offset),
 439                                            jeb->offset + je32_to_cpu(spd->offset) + je32_to_cpu(spd->totlen));
 440
 441
 442                                /* This should never happen, but https://dev.laptop.org/ticket/4184 */
 443                                checkedlen = strnlen(spd->name, spd->nsize);
 444                                if (!checkedlen) {
 445                                        printk(KERN_ERR "Dirent at %08x has zero at start of name. Aborting mount.\n",
 446                                               jeb->offset + je32_to_cpu(spd->offset));
 447                                        return -EIO;
 448                                }
 449                                if (checkedlen < spd->nsize) {
 450                                        printk(KERN_ERR "Dirent at %08x has zeroes in name. Truncating to %d chars\n",
 451                                               jeb->offset + je32_to_cpu(spd->offset), checkedlen);
 452                                }
 453
 454
 455                                fd = jffs2_alloc_full_dirent(checkedlen+1);
 456                                if (!fd)
 457                                        return -ENOMEM;
 458
 459                                memcpy(&fd->name, spd->name, checkedlen);
 460                                fd->name[checkedlen] = 0;
 461
 462                                ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(spd->pino));
 463                                if (!ic) {
 464                                        jffs2_free_full_dirent(fd);
 465                                        return -ENOMEM;
 466                                }
 467
 468                                fd->raw = sum_link_node_ref(c, jeb,  je32_to_cpu(spd->offset) | REF_UNCHECKED,
 469                                                            PAD(je32_to_cpu(spd->totlen)), ic);
 470
 471                                fd->next = NULL;
 472                                fd->version = je32_to_cpu(spd->version);
 473                                fd->ino = je32_to_cpu(spd->ino);
 474                                fd->nhash = full_name_hash(fd->name, checkedlen);
 475                                fd->type = spd->type;
 476
 477                                jffs2_add_fd_to_list(c, fd, &ic->scan_dents);
 478
 479                                *pseudo_random += je32_to_cpu(spd->version);
 480
 481                                sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize);
 482
 483                                break;
 484                        }
 485#ifdef CONFIG_JFFS2_FS_XATTR
 486                        case JFFS2_NODETYPE_XATTR: {
 487                                struct jffs2_xattr_datum *xd;
 488                                struct jffs2_sum_xattr_flash *spx;
 489
 490                                spx = (struct jffs2_sum_xattr_flash *)sp;
 491                                dbg_summary("xattr at %#08x-%#08x (xid=%u, version=%u)\n", 
 492                                            jeb->offset + je32_to_cpu(spx->offset),
 493                                            jeb->offset + je32_to_cpu(spx->offset) + je32_to_cpu(spx->totlen),
 494                                            je32_to_cpu(spx->xid), je32_to_cpu(spx->version));
 495
 496                                xd = jffs2_setup_xattr_datum(c, je32_to_cpu(spx->xid),
 497                                                                je32_to_cpu(spx->version));
 498                                if (IS_ERR(xd))
 499                                        return PTR_ERR(xd);
 500                                if (xd->version > je32_to_cpu(spx->version)) {
 501                                        /* node is not the newest one */
 502                                        struct jffs2_raw_node_ref *raw
 503                                                = sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED,
 504                                                                    PAD(je32_to_cpu(spx->totlen)), NULL);
 505                                        raw->next_in_ino = xd->node->next_in_ino;
 506                                        xd->node->next_in_ino = raw;
 507                                } else {
 508                                        xd->version = je32_to_cpu(spx->version);
 509                                        sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED,
 510                                                          PAD(je32_to_cpu(spx->totlen)), (void *)xd);
 511                                }
 512                                *pseudo_random += je32_to_cpu(spx->xid);
 513                                sp += JFFS2_SUMMARY_XATTR_SIZE;
 514
 515                                break;
 516                        }
 517                        case JFFS2_NODETYPE_XREF: {
 518                                struct jffs2_xattr_ref *ref;
 519                                struct jffs2_sum_xref_flash *spr;
 520
 521                                spr = (struct jffs2_sum_xref_flash *)sp;
 522                                dbg_summary("xref at %#08x-%#08x\n",
 523                                            jeb->offset + je32_to_cpu(spr->offset),
 524                                            jeb->offset + je32_to_cpu(spr->offset) + 
 525                                            (uint32_t)PAD(sizeof(struct jffs2_raw_xref)));
 526
 527                                ref = jffs2_alloc_xattr_ref();
 528                                if (!ref) {
 529                                        JFFS2_NOTICE("allocation of xattr_datum failed\n");
 530                                        return -ENOMEM;
 531                                }
 532                                ref->next = c->xref_temp;
 533                                c->xref_temp = ref;
 534
 535                                sum_link_node_ref(c, jeb, je32_to_cpu(spr->offset) | REF_UNCHECKED,
 536                                                  PAD(sizeof(struct jffs2_raw_xref)), (void *)ref);
 537
 538                                *pseudo_random += ref->node->flash_offset;
 539                                sp += JFFS2_SUMMARY_XREF_SIZE;
 540
 541                                break;
 542                        }
 543#endif
 544                        default : {
 545                                uint16_t nodetype = je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype);
 546                                JFFS2_WARNING("Unsupported node type %x found in summary! Exiting...\n", nodetype);
 547                                if ((nodetype & JFFS2_COMPAT_MASK) == JFFS2_FEATURE_INCOMPAT)
 548                                        return -EIO;
 549
 550                                /* For compatible node types, just fall back to the full scan */
 551                                c->wasted_size -= jeb->wasted_size;
 552                                c->free_size += c->sector_size - jeb->free_size;
 553                                c->used_size -= jeb->used_size;
 554                                c->dirty_size -= jeb->dirty_size;
 555                                jeb->wasted_size = jeb->used_size = jeb->dirty_size = 0;
 556                                jeb->free_size = c->sector_size;
 557
 558                                jffs2_free_jeb_node_refs(c, jeb);
 559                                return -ENOTRECOVERABLE;
 560                        }
 561                }
 562        }
 563        return 0;
 564}
 565
 566/* Process the summary node - called from jffs2_scan_eraseblock() */
 567int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
 568                           struct jffs2_raw_summary *summary, uint32_t sumsize,
 569                           uint32_t *pseudo_random)
 570{
 571        struct jffs2_unknown_node crcnode;
 572        int ret, ofs;
 573        uint32_t crc;
 574
 575        ofs = c->sector_size - sumsize;
 576
 577        dbg_summary("summary found for 0x%08x at 0x%08x (0x%x bytes)\n",
 578                    jeb->offset, jeb->offset + ofs, sumsize);
 579
 580        /* OK, now check for node validity and CRC */
 581        crcnode.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
 582        crcnode.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
 583        crcnode.totlen = summary->totlen;
 584        crc = crc32(0, &crcnode, sizeof(crcnode)-4);
 585
 586        if (je32_to_cpu(summary->hdr_crc) != crc) {
 587                dbg_summary("Summary node header is corrupt (bad CRC or "
 588                                "no summary at all)\n");
 589                goto crc_err;
 590        }
 591
 592        if (je32_to_cpu(summary->totlen) != sumsize) {
 593                dbg_summary("Summary node is corrupt (wrong erasesize?)\n");
 594                goto crc_err;
 595        }
 596
 597        crc = crc32(0, summary, sizeof(struct jffs2_raw_summary)-8);
 598
 599        if (je32_to_cpu(summary->node_crc) != crc) {
 600                dbg_summary("Summary node is corrupt (bad CRC)\n");
 601                goto crc_err;
 602        }
 603
 604        crc = crc32(0, summary->sum, sumsize - sizeof(struct jffs2_raw_summary));
 605
 606        if (je32_to_cpu(summary->sum_crc) != crc) {
 607                dbg_summary("Summary node data is corrupt (bad CRC)\n");
 608                goto crc_err;
 609        }
 610
 611        if ( je32_to_cpu(summary->cln_mkr) ) {
 612
 613                dbg_summary("Summary : CLEANMARKER node \n");
 614
 615                ret = jffs2_prealloc_raw_node_refs(c, jeb, 1);
 616                if (ret)
 617                        return ret;
 618
 619                if (je32_to_cpu(summary->cln_mkr) != c->cleanmarker_size) {
 620                        dbg_summary("CLEANMARKER node has totlen 0x%x != normal 0x%x\n",
 621                                je32_to_cpu(summary->cln_mkr), c->cleanmarker_size);
 622                        if ((ret = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr)))))
 623                                return ret;
 624                } else if (jeb->first_node) {
 625                        dbg_summary("CLEANMARKER node not first node in block "
 626                                        "(0x%08x)\n", jeb->offset);
 627                        if ((ret = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr)))))
 628                                return ret;
 629                } else {
 630                        jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL,
 631                                            je32_to_cpu(summary->cln_mkr), NULL);
 632                }
 633        }
 634
 635        ret = jffs2_sum_process_sum_data(c, jeb, summary, pseudo_random);
 636        /* -ENOTRECOVERABLE isn't a fatal error -- it means we should do a full
 637           scan of this eraseblock. So return zero */
 638        if (ret == -ENOTRECOVERABLE)
 639                return 0;
 640        if (ret)
 641                return ret;             /* real error */
 642
 643        /* for PARANOIA_CHECK */
 644        ret = jffs2_prealloc_raw_node_refs(c, jeb, 2);
 645        if (ret)
 646                return ret;
 647
 648        sum_link_node_ref(c, jeb, ofs | REF_NORMAL, sumsize, NULL);
 649
 650        if (unlikely(jeb->free_size)) {
 651                JFFS2_WARNING("Free size 0x%x bytes in eraseblock @0x%08x with summary?\n",
 652                              jeb->free_size, jeb->offset);
 653                jeb->wasted_size += jeb->free_size;
 654                c->wasted_size += jeb->free_size;
 655                c->free_size -= jeb->free_size;
 656                jeb->free_size = 0;
 657        }
 658
 659        return jffs2_scan_classify_jeb(c, jeb);
 660
 661crc_err:
 662        JFFS2_WARNING("Summary node crc error, skipping summary information.\n");
 663
 664        return 0;
 665}
 666
 667/* Write summary data to flash - helper function for jffs2_sum_write_sumnode() */
 668
 669static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
 670                                uint32_t infosize, uint32_t datasize, int padsize)
 671{
 672        struct jffs2_raw_summary isum;
 673        union jffs2_sum_mem *temp;
 674        struct jffs2_sum_marker *sm;
 675        struct kvec vecs[2];
 676        uint32_t sum_ofs;
 677        void *wpage;
 678        int ret;
 679        size_t retlen;
 680
 681        if (padsize + datasize > MAX_SUMMARY_SIZE) {
 682                /* It won't fit in the buffer. Abort summary for this jeb */
 683                jffs2_sum_disable_collecting(c->summary);
 684
 685                JFFS2_WARNING("Summary too big (%d data, %d pad) in eraseblock at %08x\n",
 686                              datasize, padsize, jeb->offset);
 687                /* Non-fatal */
 688                return 0;
 689        }
 690        /* Is there enough space for summary? */
 691        if (padsize < 0) {
 692                /* don't try to write out summary for this jeb */
 693                jffs2_sum_disable_collecting(c->summary);
 694
 695                JFFS2_WARNING("Not enough space for summary, padsize = %d\n",
 696                              padsize);
 697                /* Non-fatal */
 698                return 0;
 699        }
 700
 701        memset(c->summary->sum_buf, 0xff, datasize);
 702        memset(&isum, 0, sizeof(isum));
 703
 704        isum.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
 705        isum.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
 706        isum.totlen = cpu_to_je32(infosize);
 707        isum.hdr_crc = cpu_to_je32(crc32(0, &isum, sizeof(struct jffs2_unknown_node) - 4));
 708        isum.padded = cpu_to_je32(c->summary->sum_padded);
 709        isum.cln_mkr = cpu_to_je32(c->cleanmarker_size);
 710        isum.sum_num = cpu_to_je32(c->summary->sum_num);
 711        wpage = c->summary->sum_buf;
 712
 713        while (c->summary->sum_num) {
 714                temp = c->summary->sum_list_head;
 715
 716                switch (je16_to_cpu(temp->u.nodetype)) {
 717                        case JFFS2_NODETYPE_INODE: {
 718                                struct jffs2_sum_inode_flash *sino_ptr = wpage;
 719
 720                                sino_ptr->nodetype = temp->i.nodetype;
 721                                sino_ptr->inode = temp->i.inode;
 722                                sino_ptr->version = temp->i.version;
 723                                sino_ptr->offset = temp->i.offset;
 724                                sino_ptr->totlen = temp->i.totlen;
 725
 726                                wpage += JFFS2_SUMMARY_INODE_SIZE;
 727
 728                                break;
 729                        }
 730
 731                        case JFFS2_NODETYPE_DIRENT: {
 732                                struct jffs2_sum_dirent_flash *sdrnt_ptr = wpage;
 733
 734                                sdrnt_ptr->nodetype = temp->d.nodetype;
 735                                sdrnt_ptr->totlen = temp->d.totlen;
 736                                sdrnt_ptr->offset = temp->d.offset;
 737                                sdrnt_ptr->pino = temp->d.pino;
 738                                sdrnt_ptr->version = temp->d.version;
 739                                sdrnt_ptr->ino = temp->d.ino;
 740                                sdrnt_ptr->nsize = temp->d.nsize;
 741                                sdrnt_ptr->type = temp->d.type;
 742
 743                                memcpy(sdrnt_ptr->name, temp->d.name,
 744                                                        temp->d.nsize);
 745
 746                                wpage += JFFS2_SUMMARY_DIRENT_SIZE(temp->d.nsize);
 747
 748                                break;
 749                        }
 750#ifdef CONFIG_JFFS2_FS_XATTR
 751                        case JFFS2_NODETYPE_XATTR: {
 752                                struct jffs2_sum_xattr_flash *sxattr_ptr = wpage;
 753
 754                                temp = c->summary->sum_list_head;
 755                                sxattr_ptr->nodetype = temp->x.nodetype;
 756                                sxattr_ptr->xid = temp->x.xid;
 757                                sxattr_ptr->version = temp->x.version;
 758                                sxattr_ptr->offset = temp->x.offset;
 759                                sxattr_ptr->totlen = temp->x.totlen;
 760
 761                                wpage += JFFS2_SUMMARY_XATTR_SIZE;
 762                                break;
 763                        }
 764                        case JFFS2_NODETYPE_XREF: {
 765                                struct jffs2_sum_xref_flash *sxref_ptr = wpage;
 766
 767                                temp = c->summary->sum_list_head;
 768                                sxref_ptr->nodetype = temp->r.nodetype;
 769                                sxref_ptr->offset = temp->r.offset;
 770
 771                                wpage += JFFS2_SUMMARY_XREF_SIZE;
 772                                break;
 773                        }
 774#endif
 775                        default : {
 776                                if ((je16_to_cpu(temp->u.nodetype) & JFFS2_COMPAT_MASK)
 777                                    == JFFS2_FEATURE_RWCOMPAT_COPY) {
 778                                        dbg_summary("Writing unknown RWCOMPAT_COPY node type %x\n",
 779                                                    je16_to_cpu(temp->u.nodetype));
 780                                        jffs2_sum_disable_collecting(c->summary);
 781                                } else {
 782                                        BUG();  /* unknown node in summary information */
 783                                }
 784                        }
 785                }
 786
 787                c->summary->sum_list_head = temp->u.next;
 788                kfree(temp);
 789
 790                c->summary->sum_num--;
 791        }
 792
 793        jffs2_sum_reset_collected(c->summary);
 794
 795        wpage += padsize;
 796
 797        sm = wpage;
 798        sm->offset = cpu_to_je32(c->sector_size - jeb->free_size);
 799        sm->magic = cpu_to_je32(JFFS2_SUM_MAGIC);
 800
 801        isum.sum_crc = cpu_to_je32(crc32(0, c->summary->sum_buf, datasize));
 802        isum.node_crc = cpu_to_je32(crc32(0, &isum, sizeof(isum) - 8));
 803
 804        vecs[0].iov_base = &isum;
 805        vecs[0].iov_len = sizeof(isum);
 806        vecs[1].iov_base = c->summary->sum_buf;
 807        vecs[1].iov_len = datasize;
 808
 809        sum_ofs = jeb->offset + c->sector_size - jeb->free_size;
 810
 811        dbg_summary("JFFS2: writing out data to flash to pos : 0x%08x\n",
 812                    sum_ofs);
 813
 814        ret = jffs2_flash_writev(c, vecs, 2, sum_ofs, &retlen, 0);
 815
 816        if (ret || (retlen != infosize)) {
 817
 818                JFFS2_WARNING("Write of %u bytes at 0x%08x failed. returned %d, retlen %zd\n",
 819                              infosize, sum_ofs, ret, retlen);
 820
 821                if (retlen) {
 822                        /* Waste remaining space */
 823                        spin_lock(&c->erase_completion_lock);
 824                        jffs2_link_node_ref(c, jeb, sum_ofs | REF_OBSOLETE, infosize, NULL);
 825                        spin_unlock(&c->erase_completion_lock);
 826                }
 827
 828                c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE;
 829
 830                return 0;
 831        }
 832
 833        spin_lock(&c->erase_completion_lock);
 834        jffs2_link_node_ref(c, jeb, sum_ofs | REF_NORMAL, infosize, NULL);
 835        spin_unlock(&c->erase_completion_lock);
 836
 837        return 0;
 838}
 839
 840/* Write out summary information - called from jffs2_do_reserve_space */
 841
 842int jffs2_sum_write_sumnode(struct jffs2_sb_info *c)
 843{
 844        int datasize, infosize, padsize;
 845        struct jffs2_eraseblock *jeb;
 846        int ret = 0;
 847
 848        dbg_summary("called\n");
 849
 850        spin_unlock(&c->erase_completion_lock);
 851
 852        jeb = c->nextblock;
 853        jffs2_prealloc_raw_node_refs(c, jeb, 1);
 854
 855        if (!c->summary->sum_num || !c->summary->sum_list_head) {
 856                JFFS2_WARNING("Empty summary info!!!\n");
 857                BUG();
 858        }
 859
 860        datasize = c->summary->sum_size + sizeof(struct jffs2_sum_marker);
 861        infosize = sizeof(struct jffs2_raw_summary) + datasize;
 862        padsize = jeb->free_size - infosize;
 863        infosize += padsize;
 864        datasize += padsize;
 865
 866        ret = jffs2_sum_write_data(c, jeb, infosize, datasize, padsize);
 867        spin_lock(&c->erase_completion_lock);
 868        return ret;
 869}
 870