--- /dev/null
+Index: linux-2.6.5-7.201-full/include/linux/ext3_fs.h
+===================================================================
+--- linux-2.6.5-7.201-full.orig/include/linux/ext3_fs.h 2006-08-09 17:59:34.000000000 +0400
++++ linux-2.6.5-7.201-full/include/linux/ext3_fs.h 2006-08-22 12:35:55.000000000 +0400
+@@ -793,6 +793,7 @@ extern void ext3_put_super (struct super
+ extern void ext3_write_super (struct super_block *);
+ extern void ext3_write_super_lockfs (struct super_block *);
+ extern void ext3_unlockfs (struct super_block *);
++extern void ext3_commit_super (struct super_block *, struct ext3_super_block *, int);
+ extern int ext3_remount (struct super_block *, int *, char *);
+ extern int ext3_statfs (struct super_block *, struct kstatfs *);
+
+Index: linux-2.6.5-7.201-full/fs/ext3/super.c
+===================================================================
+--- linux-2.6.5-7.201-full.orig/fs/ext3/super.c 2006-08-09 17:59:37.000000000 +0400
++++ linux-2.6.5-7.201-full/fs/ext3/super.c 2006-08-09 17:59:37.000000000 +0400
+@@ -39,7 +39,7 @@
+ static int ext3_load_journal(struct super_block *, struct ext3_super_block *);
+ static int ext3_create_journal(struct super_block *, struct ext3_super_block *,
+ int);
+-static void ext3_commit_super (struct super_block * sb,
++void ext3_commit_super (struct super_block * sb,
+ struct ext3_super_block * es,
+ int sync);
+ static void ext3_mark_recovery_complete(struct super_block * sb,
+@@ -1781,7 +1781,7 @@ static int ext3_create_journal(struct su
+ return 0;
+ }
+
+-static void ext3_commit_super (struct super_block * sb,
++void ext3_commit_super (struct super_block * sb,
+ struct ext3_super_block * es,
+ int sync)
+ {
+Index: linux-2.6.5-7.201-full/fs/ext3/namei.c
+===================================================================
+--- linux-2.6.5-7.201-full.orig/fs/ext3/namei.c 2006-08-09 17:59:37.000000000 +0400
++++ linux-2.6.5-7.201-full/fs/ext3/namei.c 2006-08-09 17:59:37.000000000 +0400
+@@ -1598,7 +1598,7 @@ static int ext3_delete_entry (handle_t *
+ struct buffer_head * bh)
+ {
+ struct ext3_dir_entry_2 * de, * pde;
+- int i;
++ int i, err;
+
+ i = 0;
+ pde = NULL;
+@@ -1608,7 +1608,9 @@ static int ext3_delete_entry (handle_t *
+ return -EIO;
+ if (de == de_del) {
+ BUFFER_TRACE(bh, "get_write_access");
+- ext3_journal_get_write_access(handle, bh);
++ err = ext3_journal_get_write_access(handle, bh);
++ if (err)
++ return err;
+ if (pde)
+ pde->rec_len =
+ cpu_to_le16(le16_to_cpu(pde->rec_len) +
+Index: linux-2.6.5-7.201-full/fs/ext3/xattr.c
+===================================================================
+--- linux-2.6.5-7.201-full.orig/fs/ext3/xattr.c 2006-07-14 01:53:23.000000000 +0400
++++ linux-2.6.5-7.201-full/fs/ext3/xattr.c 2006-08-09 17:59:37.000000000 +0400
+@@ -107,7 +107,7 @@ ext3_xattr_register(int name_index, stru
+ {
+ int error = -EINVAL;
+
+- if (name_index > 0 && name_index <= EXT3_XATTR_INDEX_MAX) {
++ if (name_index > 0 && name_index < EXT3_XATTR_INDEX_MAX) {
+ write_lock(&ext3_handler_lock);
+ if (!ext3_xattr_handlers[name_index-1]) {
+ ext3_xattr_handlers[name_index-1] = handler;
+Index: linux-2.6.5-7.201-full/fs/ext3/inode.c
+===================================================================
+--- linux-2.6.5-7.201-full.orig/fs/ext3/inode.c 2006-07-14 01:53:22.000000000 +0400
++++ linux-2.6.5-7.201-full/fs/ext3/inode.c 2006-08-22 12:35:28.000000000 +0400
+@@ -1517,9 +1517,14 @@ out_stop:
+ if (end > inode->i_size) {
+ ei->i_disksize = end;
+ i_size_write(inode, end);
+- err = ext3_mark_inode_dirty(handle, inode);
+- if (!ret)
+- ret = err;
++ /*
++ * We're going to return a positive `ret'
++ * here due to non-zero-length I/O, so there's
++ * no way of reporting error returns from
++ * ext3_mark_inode_dirty() to userspace. So
++ * ignore it.
++ */
++ ext3_mark_inode_dirty(handle, inode);
+ }
+ }
+ err = ext3_journal_stop(handle);
+@@ -1811,8 +1816,18 @@ ext3_clear_blocks(handle_t *handle, stru
+ ext3_mark_inode_dirty(handle, inode);
+ ext3_journal_test_restart(handle, inode);
+ if (bh) {
++ int err;
+ BUFFER_TRACE(bh, "retaking write access");
+- ext3_journal_get_write_access(handle, bh);
++ err = ext3_journal_get_write_access(handle, bh);
++ if (err) {
++ struct super_block *sb = inode->i_sb;
++ struct ext3_super_block *es = EXT3_SB(sb)->s_es;
++ printk (KERN_CRIT"EXT3-fs: can't continue truncate\n");
++ EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS;
++ es->s_state |= cpu_to_le16(EXT3_ERROR_FS);
++ ext3_commit_super(sb, es, 1);
++ return;
++ }
+ }
+ }
+
--- /dev/null
+Index: linux-2.6.9-full/include/linux/ext3_fs.h
+===================================================================
+--- linux-2.6.9-full.orig/include/linux/ext3_fs.h 2006-08-09 17:56:39.000000000 +0400
++++ linux-2.6.9-full/include/linux/ext3_fs.h 2006-08-22 12:36:22.000000000 +0400
+@@ -826,6 +826,7 @@ extern void ext3_put_super (struct super
+ extern void ext3_write_super (struct super_block *);
+ extern void ext3_write_super_lockfs (struct super_block *);
+ extern void ext3_unlockfs (struct super_block *);
++extern void ext3_commit_super (struct super_block *, struct ext3_super_block *, int);
+ extern int ext3_remount (struct super_block *, int *, char *);
+ extern int ext3_statfs (struct super_block *, struct kstatfs *);
+
+Index: linux-2.6.9-full/fs/ext3/super.c
+===================================================================
+--- linux-2.6.9-full.orig/fs/ext3/super.c 2006-08-09 17:56:40.000000000 +0400
++++ linux-2.6.9-full/fs/ext3/super.c 2006-08-09 17:56:40.000000000 +0400
+@@ -43,7 +43,7 @@ static int ext3_load_journal(struct supe
+ unsigned long journal_devnum);
+ static int ext3_create_journal(struct super_block *, struct ext3_super_block *,
+ int);
+-static void ext3_commit_super (struct super_block * sb,
++void ext3_commit_super (struct super_block * sb,
+ struct ext3_super_block * es,
+ int sync);
+ static void ext3_mark_recovery_complete(struct super_block * sb,
+@@ -1991,7 +1991,7 @@ static int ext3_create_journal(struct su
+ return 0;
+ }
+
+-static void ext3_commit_super (struct super_block * sb,
++void ext3_commit_super (struct super_block * sb,
+ struct ext3_super_block * es,
+ int sync)
+ {
+Index: linux-2.6.9-full/fs/ext3/namei.c
+===================================================================
+--- linux-2.6.9-full.orig/fs/ext3/namei.c 2006-08-09 17:56:40.000000000 +0400
++++ linux-2.6.9-full/fs/ext3/namei.c 2006-08-09 17:56:40.000000000 +0400
+@@ -1599,7 +1599,7 @@ static int ext3_delete_entry (handle_t *
+ struct buffer_head * bh)
+ {
+ struct ext3_dir_entry_2 * de, * pde;
+- int i;
++ int i, err;
+
+ i = 0;
+ pde = NULL;
+@@ -1609,7 +1609,9 @@ static int ext3_delete_entry (handle_t *
+ return -EIO;
+ if (de == de_del) {
+ BUFFER_TRACE(bh, "get_write_access");
+- ext3_journal_get_write_access(handle, bh);
++ err = ext3_journal_get_write_access(handle, bh);
++ if (err)
++ return err;
+ if (pde)
+ pde->rec_len =
+ cpu_to_le16(le16_to_cpu(pde->rec_len) +
+Index: linux-2.6.9-full/fs/ext3/xattr.c
+===================================================================
+--- linux-2.6.9-full.orig/fs/ext3/xattr.c 2006-06-01 14:58:48.000000000 +0400
++++ linux-2.6.9-full/fs/ext3/xattr.c 2006-08-09 17:56:40.000000000 +0400
+@@ -132,7 +132,7 @@ ext3_xattr_handler(int name_index)
+ {
+ struct xattr_handler *handler = NULL;
+
+- if (name_index > 0 && name_index <= EXT3_XATTR_INDEX_MAX)
++ if (name_index > 0 && name_index < EXT3_XATTR_INDEX_MAX)
+ handler = ext3_xattr_handler_map[name_index];
+ return handler;
+ }
+Index: linux-2.6.9-full/fs/ext3/inode.c
+===================================================================
+--- linux-2.6.9-full.orig/fs/ext3/inode.c 2006-06-02 23:37:38.000000000 +0400
++++ linux-2.6.9-full/fs/ext3/inode.c 2006-08-22 12:34:28.000000000 +0400
+@@ -1513,9 +1513,14 @@ out_stop:
+ if (end > inode->i_size) {
+ ei->i_disksize = end;
+ i_size_write(inode, end);
+- err = ext3_mark_inode_dirty(handle, inode);
+- if (!ret)
+- ret = err;
++ /*
++ * We're going to return a positive `ret'
++ * here due to non-zero-length I/O, so there's
++ * no way of reporting error returns from
++ * ext3_mark_inode_dirty() to userspace. So
++ * ignore it.
++ */
++ ext3_mark_inode_dirty(handle, inode);
+ }
+ }
+ err = ext3_journal_stop(handle);
+@@ -1807,8 +1812,18 @@ ext3_clear_blocks(handle_t *handle, stru
+ ext3_mark_inode_dirty(handle, inode);
+ ext3_journal_test_restart(handle, inode);
+ if (bh) {
++ int err;
+ BUFFER_TRACE(bh, "retaking write access");
+- ext3_journal_get_write_access(handle, bh);
++ err = ext3_journal_get_write_access(handle, bh);
++ if (err) {
++ struct super_block *sb = inode->i_sb;
++ struct ext3_super_block *es = EXT3_SB(sb)->s_es;
++ printk (KERN_CRIT"EXT3-fs: can't continue truncate\n");
++ EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS;
++ es->s_state |= cpu_to_le16(EXT3_ERROR_FS);
++ ext3_commit_super(sb, es, 1);
++ return;
++ }
+ }
+ }
+
--- /dev/null
+Index: linux-stage/fs/ext3/ialloc.c
+===================================================================
+--- linux-stage.orig/fs/ext3/ialloc.c 2005-10-04 16:53:24.000000000 -0600
++++ linux-stage/fs/ext3/ialloc.c 2005-10-04 17:07:25.000000000 -0600
+@@ -629,6 +629,9 @@
+ spin_unlock(&sbi->s_next_gen_lock);
+
+ ei->i_state = EXT3_STATE_NEW;
++ ei->i_extra_isize =
++ (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) ?
++ sizeof(struct ext3_inode) - EXT3_GOOD_OLD_INODE_SIZE : 0;
+
+ ret = inode;
+ if(DQUOT_ALLOC_INODE(inode)) {
+Index: linux-stage/fs/ext3/inode.c
+===================================================================
+--- linux-stage.orig/fs/ext3/inode.c 2005-10-04 17:00:22.000000000 -0600
++++ linux-stage/fs/ext3/inode.c 2005-10-04 17:07:25.000000000 -0600
+@@ -2274,7 +2274,7 @@
+ * trying to determine the inode's location on-disk and no read need be
+ * performed.
+ */
+-static int ext3_get_inode_loc(struct inode *inode,
++int ext3_get_inode_loc(struct inode *inode,
+ struct ext3_iloc *iloc, int in_mem)
+ {
+ unsigned long block;
+@@ -2484,6 +2484,11 @@ void ext3_read_inode(struct inode * inod
+ ei->i_data[block] = raw_inode->i_block[block];
+ INIT_LIST_HEAD(&ei->i_orphan);
+
++ if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE)
++ ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize);
++ else
++ ei->i_extra_isize = 0;
++
+ if (S_ISREG(inode->i_mode)) {
+ inode->i_op = &ext3_file_inode_operations;
+ inode->i_fop = &ext3_file_operations;
+@@ -2619,6 +2624,9 @@ static int ext3_do_update_inode(handle_t
+ } else for (block = 0; block < EXT3_N_BLOCKS; block++)
+ raw_inode->i_block[block] = ei->i_data[block];
+
++ if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE)
++ raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize);
++
+ BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
+ rc = ext3_journal_dirty_metadata(handle, bh);
+ if (!err)
+@@ -2849,7 +2857,8 @@ ext3_reserve_inode_write(handle_t *handl
+ {
+ int err = 0;
+ if (handle) {
+- err = ext3_get_inode_loc(inode, iloc, 1);
++ err = ext3_get_inode_loc(inode, iloc, EXT3_I(inode)->i_state &
++ EXT3_STATE_NEW);
+ if (!err) {
+ BUFFER_TRACE(iloc->bh, "get_write_access");
+ err = ext3_journal_get_write_access(handle, iloc->bh);
+Index: linux-stage/fs/ext3/xattr.c
+===================================================================
+--- linux-stage.orig/fs/ext3/xattr.c 2005-10-04 16:50:11.000000000 -0600
++++ linux-stage/fs/ext3/xattr.c 2005-10-04 17:19:43.000000000 -0600
+@@ -149,17 +149,12 @@
+ }
+
+ /*
+- * ext3_xattr_get()
+- *
+- * Copy an extended attribute into the buffer
+- * provided, or compute the buffer size required.
+- * Buffer is NULL to compute the size of the buffer required.
++ * ext3_xattr_block_get()
+ *
+- * Returns a negative error number on failure, or the number of bytes
+- * used / required on success.
++ * routine looks for attribute in EA block and returns it's value and size
+ */
+ int
+-ext3_xattr_get(struct inode *inode, int name_index, const char *name,
++ext3_xattr_block_get(struct inode *inode, int name_index, const char *name,
+ void *buffer, size_t buffer_size)
+ {
+ struct buffer_head *bh = NULL;
+@@ -173,7 +168,6 @@
+
+ if (name == NULL)
+ return -EINVAL;
+- down_read(&EXT3_I(inode)->xattr_sem);
+ error = -ENODATA;
+ if (!EXT3_I(inode)->i_file_acl)
+ goto cleanup;
+@@ -246,15 +240,87 @@
+
+ cleanup:
+ brelse(bh);
+- up_read(&EXT3_I(inode)->xattr_sem);
+
+ return error;
+ }
+
+ /*
+- * ext3_xattr_list()
++ * ext3_xattr_ibody_get()
+ *
+- * Copy a list of attribute names into the buffer
++ * routine looks for attribute in inode body and returns it's value and size
++ */
++int
++ext3_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
++ void *buffer, size_t buffer_size)
++{
++ int size, name_len = strlen(name), storage_size;
++ struct ext3_xattr_entry *last;
++ struct ext3_inode *raw_inode;
++ struct ext3_iloc iloc;
++ char *start, *end;
++ int ret = -ENOENT;
++
++ if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
++ return -ENOENT;
++
++ ret = ext3_get_inode_loc(inode, &iloc, 0);
++ if (ret)
++ return ret;
++ raw_inode = ext3_raw_inode(&iloc);
++
++ storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
++ EXT3_GOOD_OLD_INODE_SIZE -
++ EXT3_I(inode)->i_extra_isize -
++ sizeof(__u32);
++ start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
++ EXT3_I(inode)->i_extra_isize;
++ if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
++ brelse(iloc.bh);
++ return -ENOENT;
++ }
++ start += sizeof(__u32);
++ end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
++
++ last = (struct ext3_xattr_entry *) start;
++ while (!IS_LAST_ENTRY(last)) {
++ struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
++ if (le32_to_cpu(last->e_value_size) > storage_size ||
++ (char *) next >= end) {
++ ext3_error(inode->i_sb, "ext3_xattr_ibody_get",
++ "inode %ld", inode->i_ino);
++ brelse(iloc.bh);
++ return -EIO;
++ }
++ if (name_index == last->e_name_index &&
++ name_len == last->e_name_len &&
++ !memcmp(name, last->e_name, name_len))
++ goto found;
++ last = next;
++ }
++
++ /* can't find EA */
++ brelse(iloc.bh);
++ return -ENOENT;
++
++found:
++ size = le32_to_cpu(last->e_value_size);
++ if (buffer) {
++ ret = -ERANGE;
++ if (buffer_size >= size) {
++ memcpy(buffer, start + le16_to_cpu(last->e_value_offs),
++ size);
++ ret = size;
++ }
++ } else
++ ret = size;
++ brelse(iloc.bh);
++ return ret;
++}
++
++/*
++ * ext3_xattr_get()
++ *
++ * Copy an extended attribute into the buffer
+ * provided, or compute the buffer size required.
+ * Buffer is NULL to compute the size of the buffer required.
+ *
+@@ -262,7 +328,31 @@
+ * used / required on success.
+ */
+ int
+-ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
++ext3_xattr_get(struct inode *inode, int name_index, const char *name,
++ void *buffer, size_t buffer_size)
++{
++ int err;
++
++ down_read(&EXT3_I(inode)->xattr_sem);
++
++ /* try to find attribute in inode body */
++ err = ext3_xattr_ibody_get(inode, name_index, name,
++ buffer, buffer_size);
++ if (err < 0)
++ /* search was unsuccessful, try to find EA in dedicated block */
++ err = ext3_xattr_block_get(inode, name_index, name,
++ buffer, buffer_size);
++ up_read(&EXT3_I(inode)->xattr_sem);
++
++ return err;
++}
++
++/* ext3_xattr_ibody_list()
++ *
++ * generate list of attributes stored in EA block
++ */
++int
++ext3_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size)
+ {
+ struct buffer_head *bh = NULL;
+ struct ext3_xattr_entry *entry;
+@@ -273,7 +363,6 @@
+ ea_idebug(inode, "buffer=%p, buffer_size=%ld",
+ buffer, (long)buffer_size);
+
+- down_read(&EXT3_I(inode)->xattr_sem);
+ error = 0;
+ if (!EXT3_I(inode)->i_file_acl)
+ goto cleanup;
+@@ -330,11 +419,149 @@
+
+ cleanup:
+ brelse(bh);
+- up_read(&EXT3_I(inode)->xattr_sem);
+
+ return error;
+ }
+
++/* ext3_xattr_ibody_list()
++ *
++ * generate list of attributes stored in inode body
++ */
++int
++ext3_xattr_ibody_list(struct inode *inode, char *buffer, size_t buffer_size)
++{
++ struct ext3_xattr_entry *last;
++ struct ext3_inode *raw_inode;
++ char *start, *end, *buf;
++ struct ext3_iloc iloc;
++ int storage_size;
++ size_t rest = buffer_size;
++ int ret;
++ int size = 0;
++
++ if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
++ return 0;
++
++ ret = ext3_get_inode_loc(inode, &iloc, 0);
++ if (ret)
++ return ret;
++ raw_inode = ext3_raw_inode(&iloc);
++
++ storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
++ EXT3_GOOD_OLD_INODE_SIZE -
++ EXT3_I(inode)->i_extra_isize -
++ sizeof(__u32);
++ start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
++ EXT3_I(inode)->i_extra_isize;
++ if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
++ brelse(iloc.bh);
++ return 0;
++ }
++ start += sizeof(__u32);
++ end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
++
++ last = (struct ext3_xattr_entry *) start;
++ while (!IS_LAST_ENTRY(last)) {
++ struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
++ struct xattr_handler *handler;
++ if (le32_to_cpu(last->e_value_size) > storage_size ||
++ (char *) next >= end) {
++ ext3_error(inode->i_sb, "ext3_xattr_ibody_list",
++ "inode %ld", inode->i_ino);
++ brelse(iloc.bh);
++ return -EIO;
++ }
++ handler = ext3_xattr_handler(last->e_name_index);
++ if (handler)
++ size += handler->list(inode, NULL, 0, last->e_name,
++ last->e_name_len);
++ last = next;
++ }
++
++ if (!buffer) {
++ ret = size;
++ goto cleanup;
++ } else {
++ ret = -ERANGE;
++ if (size > buffer_size)
++ goto cleanup;
++ }
++
++ last = (struct ext3_xattr_entry *) start;
++ buf = buffer;
++ while (!IS_LAST_ENTRY(last)) {
++ struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
++ struct xattr_handler *handler;
++ handler = ext3_xattr_handler(last->e_name_index);
++ if (handler) {
++ size_t size = handler->list(inode, buffer, rest,
++ last->e_name,
++ last->e_name_len);
++ if (buffer) {
++ if (size > rest) {
++ ret = -ERANGE;
++ goto cleanup;
++ }
++ buffer += size;
++ }
++ rest -= size;
++ }
++ last = next;
++ }
++ ret = size;
++cleanup:
++ brelse(iloc.bh);
++ return ret;
++}
++
++/*
++ * ext3_xattr_list()
++ *
++ * Copy a list of attribute names into the buffer
++ * provided, or compute the buffer size required.
++ * Buffer is NULL to compute the size of the buffer required.
++ *
++ * Returns a negative error number on failure, or the number of bytes
++ * used / required on success.
++ */
++int
++ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
++{
++ int error;
++ int size = buffer_size;
++
++ down_read(&EXT3_I(inode)->xattr_sem);
++
++ /* get list of attributes stored in inode body */
++ error = ext3_xattr_ibody_list(inode, buffer, buffer_size);
++ if (error < 0) {
++ /* some error occured while collecting
++ * attributes in inode body */
++ size = 0;
++ goto cleanup;
++ }
++ size = error;
++
++ /* get list of attributes stored in dedicated block */
++ if (buffer) {
++ buffer_size -= error;
++ if (buffer_size <= 0) {
++ buffer = NULL;
++ buffer_size = 0;
++ } else
++ buffer += error;
++ }
++
++ error = ext3_xattr_block_list(inode, buffer, buffer_size);
++ if (error < 0)
++ /* listing was successful, so we return len */
++ size = 0;
++
++cleanup:
++ up_read(&EXT3_I(inode)->xattr_sem);
++ return error + size;
++}
++
+ /*
+ * If the EXT3_FEATURE_COMPAT_EXT_ATTR feature of this file system is
+ * not set, set it.
+@@ -356,6 +583,279 @@
+ }
+
+ /*
++ * ext3_xattr_ibody_find()
++ *
++ * search attribute and calculate free space in inode body
++ * NOTE: free space includes space our attribute hold
++ */
++int
++ext3_xattr_ibody_find(struct inode *inode, int name_index,
++ const char *name, struct ext3_xattr_entry *rentry, int *free)
++{
++ struct ext3_xattr_entry *last;
++ struct ext3_inode *raw_inode;
++ int name_len = strlen(name);
++ int err, storage_size;
++ struct ext3_iloc iloc;
++ char *start, *end;
++ int ret = -ENOENT;
++
++ if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
++ return ret;
++
++ err = ext3_get_inode_loc(inode, &iloc, 0);
++ if (err)
++ return -EIO;
++ raw_inode = ext3_raw_inode(&iloc);
++
++ storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
++ EXT3_GOOD_OLD_INODE_SIZE -
++ EXT3_I(inode)->i_extra_isize -
++ sizeof(__u32);
++ *free = storage_size - sizeof(__u32);
++ start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
++ EXT3_I(inode)->i_extra_isize;
++ if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
++ brelse(iloc.bh);
++ return -ENOENT;
++ }
++ start += sizeof(__u32);
++ end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
++
++ last = (struct ext3_xattr_entry *) start;
++ while (!IS_LAST_ENTRY(last)) {
++ struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
++ if (le32_to_cpu(last->e_value_size) > storage_size ||
++ (char *) next >= end) {
++ ext3_error(inode->i_sb, "ext3_xattr_ibody_find",
++ "inode %ld", inode->i_ino);
++ brelse(iloc.bh);
++ return -EIO;
++ }
++
++ if (name_index == last->e_name_index &&
++ name_len == last->e_name_len &&
++ !memcmp(name, last->e_name, name_len)) {
++ memcpy(rentry, last, sizeof(struct ext3_xattr_entry));
++ ret = 0;
++ } else {
++ *free -= EXT3_XATTR_LEN(last->e_name_len);
++ *free -= le32_to_cpu(last->e_value_size);
++ }
++ last = next;
++ }
++
++ brelse(iloc.bh);
++ return ret;
++}
++
++/*
++ * ext3_xattr_block_find()
++ *
++ * search attribute and calculate free space in EA block (if it allocated)
++ * NOTE: free space includes space our attribute hold
++ */
++int
++ext3_xattr_block_find(struct inode *inode, int name_index, const char *name,
++ struct ext3_xattr_entry *rentry, int *free)
++{
++ struct buffer_head *bh = NULL;
++ struct ext3_xattr_entry *entry;
++ char *end;
++ int name_len, error = -ENOENT;
++
++ if (!EXT3_I(inode)->i_file_acl) {
++ *free = inode->i_sb->s_blocksize -
++ sizeof(struct ext3_xattr_header) -
++ sizeof(__u32);
++ return -ENOENT;
++ }
++ ea_idebug(inode, "reading block %d", EXT3_I(inode)->i_file_acl);
++ bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);
++ if (!bh)
++ return -EIO;
++ ea_bdebug(bh, "b_count=%d, refcount=%d",
++ atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount));
++ end = bh->b_data + bh->b_size;
++ if (HDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) ||
++ HDR(bh)->h_blocks != cpu_to_le32(1)) {
++bad_block: ext3_error(inode->i_sb, "ext3_xattr_get",
++ "inode %ld: bad block %d", inode->i_ino,
++ EXT3_I(inode)->i_file_acl);
++ brelse(bh);
++ return -EIO;
++ }
++ /* find named attribute */
++ name_len = strlen(name);
++ *free = bh->b_size - sizeof(__u32);
++
++ entry = FIRST_ENTRY(bh);
++ while (!IS_LAST_ENTRY(entry)) {
++ struct ext3_xattr_entry *next =
++ EXT3_XATTR_NEXT(entry);
++ if ((char *)next >= end)
++ goto bad_block;
++ if (name_index == entry->e_name_index &&
++ name_len == entry->e_name_len &&
++ memcmp(name, entry->e_name, name_len) == 0) {
++ memcpy(rentry, entry, sizeof(struct ext3_xattr_entry));
++ error = 0;
++ } else {
++ *free -= EXT3_XATTR_LEN(entry->e_name_len);
++ *free -= le32_to_cpu(entry->e_value_size);
++ }
++ entry = next;
++ }
++ brelse(bh);
++
++ return error;
++}
++
++/*
++ * ext3_xattr_inode_set()
++ *
++ * this routine add/remove/replace attribute in inode body
++ */
++int
++ext3_xattr_ibody_set(handle_t *handle, struct inode *inode, int name_index,
++ const char *name, const void *value, size_t value_len,
++ int flags)
++{
++ struct ext3_xattr_entry *last, *next, *here = NULL;
++ struct ext3_inode *raw_inode;
++ int name_len = strlen(name);
++ int esize = EXT3_XATTR_LEN(name_len);
++ struct buffer_head *bh;
++ int err, storage_size;
++ struct ext3_iloc iloc;
++ int free, min_offs;
++ char *start, *end;
++
++ if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
++ return -ENOSPC;
++
++ err = ext3_get_inode_loc(inode, &iloc, 0);
++ if (err)
++ return err;
++ raw_inode = ext3_raw_inode(&iloc);
++ bh = iloc.bh;
++
++ storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
++ EXT3_GOOD_OLD_INODE_SIZE -
++ EXT3_I(inode)->i_extra_isize -
++ sizeof(__u32);
++ start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
++ EXT3_I(inode)->i_extra_isize;
++ if ((*(__u32*) start) != EXT3_XATTR_MAGIC) {
++ /* inode had no attributes before */
++ *((__u32*) start) = cpu_to_le32(EXT3_XATTR_MAGIC);
++ }
++ start += sizeof(__u32);
++ end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
++ min_offs = storage_size;
++ free = storage_size - sizeof(__u32);
++
++ last = (struct ext3_xattr_entry *) start;
++ while (!IS_LAST_ENTRY(last)) {
++ next = EXT3_XATTR_NEXT(last);
++ if (le32_to_cpu(last->e_value_size) > storage_size ||
++ (char *) next >= end) {
++ ext3_error(inode->i_sb, "ext3_xattr_ibody_set",
++ "inode %ld", inode->i_ino);
++ brelse(bh);
++ return -EIO;
++ }
++
++ if (last->e_value_size) {
++ int offs = le16_to_cpu(last->e_value_offs);
++ if (offs < min_offs)
++ min_offs = offs;
++ }
++ if (name_index == last->e_name_index &&
++ name_len == last->e_name_len &&
++ !memcmp(name, last->e_name, name_len))
++ here = last;
++ else {
++ /* we calculate all but&nbs