Merge git://git.infradead.org/mtd-2.6
KaiGai Kohei [Thu, 18 May 2006 15:43:53 +0000 (00:43 +0900)]
1  2 
fs/jffs2/file.c
fs/jffs2/nodelist.c
fs/jffs2/scan.c
fs/jffs2/summary.c
fs/jffs2/super.c
include/linux/jffs2.h

diff --combined fs/jffs2/file.c
@@@ -54,12 -54,7 +54,12 @@@ const struct file_operations jffs2_file
  
  struct inode_operations jffs2_file_inode_operations =
  {
 -      .setattr =      jffs2_setattr
 +      .permission =   jffs2_permission,
 +      .setattr =      jffs2_setattr,
 +      .setxattr =     jffs2_setxattr,
 +      .getxattr =     jffs2_getxattr,
 +      .listxattr =    jffs2_listxattr,
 +      .removexattr =  jffs2_removexattr
  };
  
  struct address_space_operations jffs2_file_address_operations =
@@@ -220,12 -215,20 +220,20 @@@ static int jffs2_commit_write (struct f
        D1(printk(KERN_DEBUG "jffs2_commit_write(): ino #%lu, page at 0x%lx, range %d-%d, flags %lx\n",
                  inode->i_ino, pg->index << PAGE_CACHE_SHIFT, start, end, pg->flags));
  
-       if (!start && end == PAGE_CACHE_SIZE) {
-               /* We need to avoid deadlock with page_cache_read() in
-                  jffs2_garbage_collect_pass(). So we have to mark the
-                  page up to date, to prevent page_cache_read() from
-                  trying to re-lock it. */
-               SetPageUptodate(pg);
+       if (end == PAGE_CACHE_SIZE) {
+               if (!start) {
+                       /* We need to avoid deadlock with page_cache_read() in
+                          jffs2_garbage_collect_pass(). So we have to mark the
+                          page up to date, to prevent page_cache_read() from
+                          trying to re-lock it. */
+                       SetPageUptodate(pg);
+               } else {
+                       /* When writing out the end of a page, write out the 
+                          _whole_ page. This helps to reduce the number of
+                          nodes in files which have many short writes, like
+                          syslog files. */
+                       start = aligned_start = 0;
+               }
        }
  
        ri = jffs2_alloc_raw_inode();
diff --combined fs/jffs2/nodelist.c
@@@ -438,7 -438,7 +438,7 @@@ static int check_node_data(struct jffs2
        if (c->mtd->point) {
                err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer);
                if (!err && retlen < tn->csize) {
-                       JFFS2_WARNING("MTD point returned len too short: %u instead of %u.\n", retlen, tn->csize);
+                       JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize);
                        c->mtd->unpoint(c->mtd, buffer, ofs, len);
                } else if (err)
                        JFFS2_WARNING("MTD point failed: error code %d.\n", err);
                }
  
                if (retlen != len) {
-                       JFFS2_ERROR("short read at %#08x: %d instead of %d.\n", ofs, retlen, len);
+                       JFFS2_ERROR("short read at %#08x: %zd instead of %d.\n", ofs, retlen, len);
                        err = -EIO;
                        goto free_out;
                }
@@@ -938,7 -938,6 +938,7 @@@ void jffs2_free_ino_caches(struct jffs2
                this = c->inocache_list[i];
                while (this) {
                        next = this->next;
 +                      jffs2_xattr_free_inode(c, this);
                        jffs2_free_inode_cache(this);
                        this = next;
                }
diff --combined fs/jffs2/scan.c
@@@ -222,9 -222,6 +222,6 @@@ int jffs2_scan_medium(struct jffs2_sb_i
                }
        }
  
-       if (jffs2_sum_active() && s)
-               kfree(s);
        /* Nextblock dirty is always seen as wasted, because we cannot recycle it now */
        if (c->nextblock && (c->nextblock->dirty_size)) {
                c->nextblock->wasted_size += c->nextblock->dirty_size;
        else
                c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size);
  #endif
+       if (s)
+               kfree(s);
        return ret;
  }
  
@@@ -306,137 -306,6 +306,137 @@@ int jffs2_scan_classify_jeb(struct jffs
                return BLK_STATE_ALLDIRTY;
  }
  
 +#ifdef CONFIG_JFFS2_FS_XATTR
 +static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
 +                               struct jffs2_raw_xattr *rx, uint32_t ofs,
 +                               struct jffs2_summary *s)
 +{
 +      struct jffs2_xattr_datum *xd;
 +      struct jffs2_raw_node_ref *raw;
 +      uint32_t totlen, crc;
 +
 +      crc = crc32(0, rx, sizeof(struct jffs2_raw_xattr) - 4);
 +      if (crc != je32_to_cpu(rx->node_crc)) {
 +              if (je32_to_cpu(rx->node_crc) != 0xffffffff)
 +                      JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
 +                                    ofs, je32_to_cpu(rx->node_crc), crc);
 +              DIRTY_SPACE(je32_to_cpu(rx->totlen));
 +              return 0;
 +      }
 +
 +      totlen = PAD(sizeof(*rx) + rx->name_len + 1 + je16_to_cpu(rx->value_len));
 +      if (totlen != je32_to_cpu(rx->totlen)) {
 +              JFFS2_WARNING("node length mismatch at %#08x, read=%u, calc=%u\n",
 +                            ofs, je32_to_cpu(rx->totlen), totlen);
 +              DIRTY_SPACE(je32_to_cpu(rx->totlen));
 +              return 0;
 +      }
 +
 +      raw =  jffs2_alloc_raw_node_ref();
 +      if (!raw)
 +              return -ENOMEM;
 +
 +      xd = jffs2_setup_xattr_datum(c, je32_to_cpu(rx->xid), je32_to_cpu(rx->version));
 +      if (IS_ERR(xd)) {
 +              jffs2_free_raw_node_ref(raw);
 +              if (PTR_ERR(xd) == -EEXIST) {
 +                      DIRTY_SPACE(PAD(je32_to_cpu(rx->totlen)));
 +                      return 0;
 +              }
 +              return PTR_ERR(xd);
 +      }
 +      xd->xprefix = rx->xprefix;
 +      xd->name_len = rx->name_len;
 +      xd->value_len = je16_to_cpu(rx->value_len);
 +      xd->data_crc = je32_to_cpu(rx->data_crc);
 +      xd->node = raw;
 +
 +      raw->__totlen = totlen;
 +      raw->flash_offset = ofs | REF_PRISTINE;
 +      raw->next_phys = NULL;
 +      raw->next_in_ino = (void *)xd;
 +      if (!jeb->first_node)
 +              jeb->first_node = raw;
 +      if (jeb->last_node)
 +              jeb->last_node->next_phys = raw;
 +      jeb->last_node = raw;
 +
 +      USED_SPACE(PAD(je32_to_cpu(rx->totlen)));
 +      if (jffs2_sum_active())
 +              jffs2_sum_add_xattr_mem(s, rx, ofs - jeb->offset);
 +      dbg_xattr("scaning xdatum at %#08x (xid=%u, version=%u)\n",
 +                ofs, xd->xid, xd->version);
 +      return 0;
 +}
 +
 +static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
 +                              struct jffs2_raw_xref *rr, uint32_t ofs,
 +                              struct jffs2_summary *s)
 +{
 +      struct jffs2_xattr_ref *ref;
 +      struct jffs2_raw_node_ref *raw;
 +      uint32_t crc;
 +
 +      crc = crc32(0, rr, sizeof(*rr) - 4);
 +      if (crc != je32_to_cpu(rr->node_crc)) {
 +              if (je32_to_cpu(rr->node_crc) != 0xffffffff)
 +                      JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
 +                                    ofs, je32_to_cpu(rr->node_crc), crc);
 +              DIRTY_SPACE(PAD(je32_to_cpu(rr->totlen)));
 +              return 0;
 +      }
 +
 +      if (PAD(sizeof(struct jffs2_raw_xref)) != je32_to_cpu(rr->totlen)) {
 +              JFFS2_WARNING("node length mismatch at %#08x, read=%u, calc=%u\n",
 +                            ofs, je32_to_cpu(rr->totlen),
 +                            PAD(sizeof(struct jffs2_raw_xref)));
 +              DIRTY_SPACE(je32_to_cpu(rr->totlen));
 +              return 0;
 +      }
 +
 +      ref = jffs2_alloc_xattr_ref();
 +      if (!ref)
 +              return -ENOMEM;
 +
 +      raw =  jffs2_alloc_raw_node_ref();
 +      if (!raw) {
 +              jffs2_free_xattr_ref(ref);
 +              return -ENOMEM;
 +      }
 +
 +      /* BEFORE jffs2_build_xattr_subsystem() called, 
 +       * ref->xid is used to store 32bit xid, xd is not used
 +       * ref->ino is used to store 32bit inode-number, ic is not used
 +       * Thoes variables are declared as union, thus using those
 +       * are exclusive. In a similar way, ref->next is temporarily
 +       * used to chain all xattr_ref object. It's re-chained to
 +       * jffs2_inode_cache in jffs2_build_xattr_subsystem() correctly.
 +       */
 +      ref->node = raw;
 +      ref->ino = je32_to_cpu(rr->ino);
 +      ref->xid = je32_to_cpu(rr->xid);
 +      ref->next = c->xref_temp;
 +      c->xref_temp = ref;
 +
 +      raw->__totlen = PAD(je32_to_cpu(rr->totlen));
 +      raw->flash_offset = ofs | REF_PRISTINE;
 +      raw->next_phys = NULL;
 +      raw->next_in_ino = (void *)ref;
 +      if (!jeb->first_node)
 +              jeb->first_node = raw;
 +      if (jeb->last_node)
 +              jeb->last_node->next_phys = raw;
 +      jeb->last_node = raw;
 +
 +      USED_SPACE(PAD(je32_to_cpu(rr->totlen)));       
 +      if (jffs2_sum_active())
 +              jffs2_sum_add_xref_mem(s, rr, ofs - jeb->offset);
 +      dbg_xattr("scan xref at %#08x (xid=%u, ino=%u)\n",
 +                ofs, ref->xid, ref->ino);
 +      return 0;
 +}
 +#endif
 +
  static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
                                unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s) {
        struct jffs2_unknown_node *node;
@@@ -745,43 -614,6 +745,43 @@@ scan_more
                        ofs += PAD(je32_to_cpu(node->totlen));
                        break;
  
 +#ifdef CONFIG_JFFS2_FS_XATTR
 +              case JFFS2_NODETYPE_XATTR:
 +                      if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
 +                              buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
 +                              D1(printk(KERN_DEBUG "Fewer than %d bytes (xattr node)"
 +                                        " left to end of buf. Reading 0x%x at 0x%08x\n",
 +                                        je32_to_cpu(node->totlen), buf_len, ofs));
 +                              err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
 +                              if (err)
 +                                      return err;
 +                              buf_ofs = ofs;
 +                              node = (void *)buf;
 +                      }
 +                      err = jffs2_scan_xattr_node(c, jeb, (void *)node, ofs, s);
 +                      if (err)
 +                              return err;
 +                      ofs += PAD(je32_to_cpu(node->totlen));
 +                      break;
 +              case JFFS2_NODETYPE_XREF:
 +                      if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
 +                              buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
 +                              D1(printk(KERN_DEBUG "Fewer than %d bytes (xref node)"
 +                                        " left to end of buf. Reading 0x%x at 0x%08x\n",
 +                                        je32_to_cpu(node->totlen), buf_len, ofs));
 +                              err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
 +                              if (err)
 +                                      return err;
 +                              buf_ofs = ofs;
 +                              node = (void *)buf;
 +                      }
 +                      err = jffs2_scan_xref_node(c, jeb, (void *)node, ofs, s);
 +                      if (err)
 +                              return err;
 +                      ofs += PAD(je32_to_cpu(node->totlen));
 +                      break;
 +#endif        /* CONFIG_JFFS2_FS_XATTR */
 +
                case JFFS2_NODETYPE_CLEANMARKER:
                        D1(printk(KERN_DEBUG "CLEANMARKER node found at 0x%08x\n", ofs));
                        if (je32_to_cpu(node->totlen) != c->cleanmarker_size) {
diff --combined fs/jffs2/summary.c
@@@ -5,7 -5,6 +5,7 @@@
   *                     Zoltan Sogor <weth@inf.u-szeged.hu>,
   *                     Patrik Kluba <pajko@halom.u-szeged.hu>,
   *                     University of Szeged, Hungary
 + *               2005  KaiGai Kohei <kaigai@ak.jp.nec.com>
   *
   * For licensing information, see the file 'LICENCE' in this directory.
   *
@@@ -82,19 -81,6 +82,19 @@@ static int jffs2_sum_add_mem(struct jff
                        dbg_summary("dirent (%u) added to summary\n",
                                                je32_to_cpu(item->d.ino));
                        break;
 +#ifdef CONFIG_JFFS2_FS_XATTR
 +              case JFFS2_NODETYPE_XATTR:
 +                      s->sum_size += JFFS2_SUMMARY_XATTR_SIZE;
 +                      s->sum_num++;
 +                      dbg_summary("xattr (xid=%u, version=%u) added to summary\n",
 +                                  je32_to_cpu(item->x.xid), je32_to_cpu(item->x.version));
 +                      break;
 +              case JFFS2_NODETYPE_XREF:
 +                      s->sum_size += JFFS2_SUMMARY_XREF_SIZE;
 +                      s->sum_num++;
 +                      dbg_summary("xref added to summary\n");
 +                      break;
 +#endif
                default:
                        JFFS2_WARNING("UNKNOWN node type %u\n",
                                            je16_to_cpu(item->u.nodetype));
@@@ -155,40 -141,6 +155,40 @@@ int jffs2_sum_add_dirent_mem(struct jff
        return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
  }
  
 +#ifdef CONFIG_JFFS2_FS_XATTR
 +int jffs2_sum_add_xattr_mem(struct jffs2_summary *s, struct jffs2_raw_xattr *rx, uint32_t ofs)
 +{
 +      struct jffs2_sum_xattr_mem *temp;
 +
 +      temp = kmalloc(sizeof(struct jffs2_sum_xattr_mem), GFP_KERNEL);
 +      if (!temp)
 +              return -ENOMEM;
 +
 +      temp->nodetype = rx->nodetype;
 +      temp->xid = rx->xid;
 +      temp->version = rx->version;
 +      temp->offset = cpu_to_je32(ofs);
 +      temp->totlen = rx->totlen;
 +      temp->next = NULL;
 +
 +      return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
 +}
 +
 +int jffs2_sum_add_xref_mem(struct jffs2_summary *s, struct jffs2_raw_xref *rr, uint32_t ofs)
 +{
 +      struct jffs2_sum_xref_mem *temp;
 +
 +      temp = kmalloc(sizeof(struct jffs2_sum_xref_mem), GFP_KERNEL);
 +      if (!temp)
 +              return -ENOMEM;
 +
 +      temp->nodetype = rr->nodetype;
 +      temp->offset = cpu_to_je32(ofs);
 +      temp->next = NULL;
 +
 +      return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
 +}
 +#endif
  /* Cleanup every collected summary information */
  
  static void jffs2_sum_clean_collected(struct jffs2_summary *s)
@@@ -307,40 -259,7 +307,40 @@@ int jffs2_sum_add_kvec(struct jffs2_sb_
  
                        return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
                }
 +#ifdef CONFIG_JFFS2_FS_XATTR
 +              case JFFS2_NODETYPE_XATTR: {
 +                      struct jffs2_sum_xattr_mem *temp;
 +                      if (je32_to_cpu(node->x.version) == 0xffffffff)
 +                              return 0;
 +                      temp = kmalloc(sizeof(struct jffs2_sum_xattr_mem), GFP_KERNEL);
 +                      if (!temp)
 +                              goto no_mem;
 +
 +                      temp->nodetype = node->x.nodetype;
 +                      temp->xid = node->x.xid;
 +                      temp->version = node->x.version;
 +                      temp->totlen = node->x.totlen;
 +                      temp->offset = cpu_to_je32(ofs);
 +                      temp->next = NULL;
 +
 +                      return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
 +              }
 +              case JFFS2_NODETYPE_XREF: {
 +                      struct jffs2_sum_xref_mem *temp;
  
 +                      if (je32_to_cpu(node->r.ino) == 0xffffffff
 +                          && je32_to_cpu(node->r.xid) == 0xffffffff)
 +                              return 0;
 +                      temp = kmalloc(sizeof(struct jffs2_sum_xref_mem), GFP_KERNEL);
 +                      if (!temp)
 +                              goto no_mem;
 +                      temp->nodetype = node->r.nodetype;
 +                      temp->offset = cpu_to_je32(ofs);
 +                      temp->next = NULL;
 +
 +                      return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
 +              }
 +#endif
                case JFFS2_NODETYPE_PADDING:
                        dbg_summary("node PADDING\n");
                        c->summary->sum_padded += je32_to_cpu(node->u.totlen);
@@@ -489,101 -408,8 +489,101 @@@ static int jffs2_sum_process_sum_data(s
  
                                break;
                        }
 +#ifdef CONFIG_JFFS2_FS_XATTR
 +                      case JFFS2_NODETYPE_XATTR: {
 +                              struct jffs2_xattr_datum *xd;
 +                              struct jffs2_sum_xattr_flash *spx;
 +                              uint32_t ofs;
 +
 +                              spx = (struct jffs2_sum_xattr_flash *)sp;
 +                              ofs = jeb->offset + je32_to_cpu(spx->offset);
 +                              dbg_summary("xattr at %#08x (xid=%u, version=%u)\n", ofs,
 +                                          je32_to_cpu(spx->xid), je32_to_cpu(spx->version));
 +                              raw = jffs2_alloc_raw_node_ref();
 +                              if (!raw) {
 +                                      JFFS2_NOTICE("allocation of node reference failed\n");
 +                                      kfree(summary);
 +                                      return -ENOMEM;
 +                              }
 +                              xd = jffs2_setup_xattr_datum(c, je32_to_cpu(spx->xid),
 +                                                              je32_to_cpu(spx->version));
 +                              if (IS_ERR(xd)) {
 +                                      jffs2_free_raw_node_ref(raw);
 +                                      if (PTR_ERR(xd) == -EEXIST) {
 +                                              /* a newer version of xd exists */
 +                                              DIRTY_SPACE(je32_to_cpu(spx->totlen));
 +                                              sp += JFFS2_SUMMARY_XATTR_SIZE;
 +                                              break;
 +                                      }
 +                                      JFFS2_NOTICE("allocation of xattr_datum failed\n");
 +                                      kfree(summary);
 +                                      return PTR_ERR(xd);
 +                              }
 +                              xd->node = raw;
 +
 +                              raw->flash_offset = ofs | REF_UNCHECKED;
 +                              raw->__totlen = PAD(je32_to_cpu(spx->totlen));
 +                              raw->next_phys = NULL;
 +                              raw->next_in_ino = (void *)xd;
 +                              if (!jeb->first_node)
 +                                      jeb->first_node = raw;
 +                              if (jeb->last_node)
 +                                      jeb->last_node->next_phys = raw;
 +                              jeb->last_node = raw;
 +
 +                              *pseudo_random += je32_to_cpu(spx->xid);
 +                              UNCHECKED_SPACE(je32_to_cpu(spx->totlen));
 +                              sp += JFFS2_SUMMARY_XATTR_SIZE;
 +
 +                              break;
 +                      }
 +                      case JFFS2_NODETYPE_XREF: {
 +                              struct jffs2_xattr_ref *ref;
 +                              struct jffs2_sum_xref_flash *spr;
 +                              uint32_t ofs;
 +
 +                              spr = (struct jffs2_sum_xref_flash *)sp;
 +                              ofs = jeb->offset + je32_to_cpu(spr->offset);
 +                              dbg_summary("xref at %#08x (xid=%u, ino=%u)\n", ofs,
 +                                          je32_to_cpu(spr->xid), je32_to_cpu(spr->ino));
 +                              raw = jffs2_alloc_raw_node_ref();
 +                              if (!raw) {
 +                                      JFFS2_NOTICE("allocation of node reference failed\n");
 +                                      kfree(summary);
 +                                      return -ENOMEM;
 +                              }
 +                              ref = jffs2_alloc_xattr_ref();
 +                              if (!ref) {
 +                                      JFFS2_NOTICE("allocation of xattr_datum failed\n");
 +                                      jffs2_free_raw_node_ref(raw);
 +                                      kfree(summary);
 +                                      return -ENOMEM;
 +                              }
 +                              ref->ino = 0xfffffffe;
 +                              ref->xid = 0xfffffffd;
 +                              ref->node = raw;
 +                              ref->next = c->xref_temp;
 +                              c->xref_temp = ref;
 +
 +                              raw->__totlen = PAD(sizeof(struct jffs2_raw_xref));
 +                              raw->flash_offset = ofs | REF_UNCHECKED;
 +                              raw->next_phys = NULL;
 +                              raw->next_in_ino = (void *)ref;
 +                              if (!jeb->first_node)
 +                                      jeb->first_node = raw;
 +                              if (jeb->last_node)
 +                                      jeb->last_node->next_phys = raw;
 +                              jeb->last_node = raw;
 +
 +                              UNCHECKED_SPACE(PAD(sizeof(struct jffs2_raw_xref)));
 +                              *pseudo_random += ofs;
 +                              sp += JFFS2_SUMMARY_XREF_SIZE;
  
 +                              break;
 +                      }
 +#endif
                        default : {
 +printk("nodetype = %#04x\n",je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype));
                                JFFS2_WARNING("Unsupported node type found in summary! Exiting...");
                                kfree(summary);
                                return -EIO;
@@@ -791,31 -617,7 +791,31 @@@ static int jffs2_sum_write_data(struct 
  
                                break;
                        }
 +#ifdef CONFIG_JFFS2_FS_XATTR
 +                      case JFFS2_NODETYPE_XATTR: {
 +                              struct jffs2_sum_xattr_flash *sxattr_ptr = wpage;
 +
 +                              temp = c->summary->sum_list_head;
 +                              sxattr_ptr->nodetype = temp->x.nodetype;
 +                              sxattr_ptr->xid = temp->x.xid;
 +                              sxattr_ptr->version = temp->x.version;
 +                              sxattr_ptr->offset = temp->x.offset;
 +                              sxattr_ptr->totlen = temp->x.totlen;
 +
 +                              wpage += JFFS2_SUMMARY_XATTR_SIZE;
 +                              break;
 +                      }
 +                      case JFFS2_NODETYPE_XREF: {
 +                              struct jffs2_sum_xref_flash *sxref_ptr = wpage;
 +
 +                              temp = c->summary->sum_list_head;
 +                              sxref_ptr->nodetype = temp->r.nodetype;
 +                              sxref_ptr->offset = temp->r.offset;
  
 +                              wpage += JFFS2_SUMMARY_XREF_SIZE;
 +                              break;
 +                      }
 +#endif
                        default : {
                                BUG();  /* unknown node in summary information */
                        }
  
  
        if (ret || (retlen != infosize)) {
-               JFFS2_WARNING("Write of %d bytes at 0x%08x failed. returned %d, retlen %zu\n",
+               JFFS2_WARNING("Write of %u bytes at 0x%08x failed. returned %d, retlen %zd\n",
                        infosize, jeb->offset + c->sector_size - jeb->free_size, ret, retlen);
  
                c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE;
diff --combined fs/jffs2/super.c
@@@ -151,10 -151,7 +151,10 @@@ static struct super_block *jffs2_get_sb
  
        sb->s_op = &jffs2_super_operations;
        sb->s_flags = flags | MS_NOATIME;
 -
 +      sb->s_xattr = jffs2_xattr_handlers;
 +#ifdef CONFIG_JFFS2_FS_POSIX_ACL
 +      sb->s_flags |= MS_POSIXACL;
 +#endif
        ret = jffs2_do_fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
  
        if (ret) {
@@@ -296,7 -293,6 +296,7 @@@ static void jffs2_put_super (struct sup
                kfree(c->blocks);
        jffs2_flash_cleanup(c);
        kfree(c->inocache_list);
 +      jffs2_clear_xattr_subsystem(c);
        if (c->mtd->sync)
                c->mtd->sync(c->mtd);
  
@@@ -324,6 -320,18 +324,18 @@@ static int __init init_jffs2_fs(void
  {
        int ret;
  
+       /* Paranoia checks for on-medium structures. If we ask GCC
+          to pack them with __attribute__((packed)) then it _also_
+          assumes that they're not aligned -- so it emits crappy
+          code on some architectures. Ideally we want an attribute
+          which means just 'no padding', without the alignment
+          thing. But GCC doesn't have that -- we have to just
+          hope the structs are the right sizes, instead. */
+       BUG_ON(sizeof(struct jffs2_unknown_node) != 12);
+       BUG_ON(sizeof(struct jffs2_raw_dirent) != 40);
+       BUG_ON(sizeof(struct jffs2_raw_inode) != 68);
+       BUG_ON(sizeof(struct jffs2_raw_summary) != 32);
        printk(KERN_INFO "JFFS2 version 2.2."
  #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
               " (NAND)"
  #ifdef CONFIG_JFFS2_SUMMARY
               " (SUMMARY) "
  #endif
-              " (C) 2001-2003 Red Hat, Inc.\n");
+              " (C) 2001-2006 Red Hat, Inc.\n");
  
        jffs2_inode_cachep = kmem_cache_create("jffs2_i",
                                             sizeof(struct jffs2_inode_info),
diff --combined include/linux/jffs2.h
  
  #define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6)
  
 +#define JFFS2_NODETYPE_XATTR (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 8)
 +#define JFFS2_NODETYPE_XREF (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 9)
 +
 +/* XATTR Related */
 +#define JFFS2_XPREFIX_USER            1       /* for "user." */
 +#define JFFS2_XPREFIX_SECURITY                2       /* for "security." */
 +#define JFFS2_XPREFIX_ACL_ACCESS      3       /* for "system.posix_acl_access" */
 +#define JFFS2_XPREFIX_ACL_DEFAULT     4       /* for "system.posix_acl_default" */
 +#define JFFS2_XPREFIX_TRUSTED         5       /* for "trusted.*" */
 +
 +#define JFFS2_ACL_VERSION             0x0001
 +
  // Maybe later...
  //#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
  //#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4)
  
  typedef struct {
        uint32_t v32;
- } __attribute__((packed))  jint32_t;
+ } __attribute__((packed)) jint32_t;
  
  typedef struct {
        uint32_t m;
- } __attribute__((packed))  jmode_t;
+ } __attribute__((packed)) jmode_t;
  
  typedef struct {
        uint16_t v16;
@@@ -111,7 -99,7 +111,7 @@@ struct jffs2_unknown_nod
        jint16_t nodetype;
        jint32_t totlen; /* So we can skip over nodes we don't grok */
        jint32_t hdr_crc;
- } __attribute__((packed));
+ };
  
  struct jffs2_raw_dirent
  {
        jint32_t node_crc;
        jint32_t name_crc;
        uint8_t name[0];
- } __attribute__((packed));
+ };
  
  /* The JFFS2 raw inode structure: Used for storage on physical media.  */
  /* The uid, gid, atime, mtime and ctime members could be longer, but
@@@ -161,34 -149,8 +161,34 @@@ struct jffs2_raw_inod
        jint32_t data_crc;   /* CRC for the (compressed) data.  */
        jint32_t node_crc;   /* CRC for the raw inode (excluding data)  */
        uint8_t data[0];
- } __attribute__((packed));
+ };
  
 +struct jffs2_raw_xattr {
 +      jint16_t magic;
 +      jint16_t nodetype;      /* = JFFS2_NODETYPE_XATTR */
 +      jint32_t totlen;
 +      jint32_t hdr_crc;
 +      jint32_t xid;           /* XATTR identifier number */
 +      jint32_t version;
 +      uint8_t xprefix;
 +      uint8_t name_len;
 +      jint16_t value_len;
 +      jint32_t data_crc;
 +      jint32_t node_crc;
 +      uint8_t data[0];
 +} __attribute__((packed));
 +
 +struct jffs2_raw_xref
 +{
 +      jint16_t magic;
 +      jint16_t nodetype;      /* = JFFS2_NODETYPE_XREF */
 +      jint32_t totlen;
 +      jint32_t hdr_crc;
 +      jint32_t ino;           /* inode number */
 +      jint32_t xid;           /* XATTR identifier number */
 +      jint32_t node_crc;
 +} __attribute__((packed));
 +
  struct jffs2_raw_summary
  {
        jint16_t magic;
        jint32_t sum_crc;       /* summary information crc */
        jint32_t node_crc;      /* node crc */
        jint32_t sum[0];        /* inode summary info */
- } __attribute__((packed));
+ };
  
  union jffs2_node_union
  {
        struct jffs2_raw_inode i;
        struct jffs2_raw_dirent d;
 +      struct jffs2_raw_xattr x;
 +      struct jffs2_raw_xref r;
        struct jffs2_raw_summary s;
        struct jffs2_unknown_node u;
  };