Index: linux-2.6.10/fs/ext3/xattr.h =================================================================== --- linux-2.6.10.orig/fs/ext3/xattr.h 2005-04-05 12:26:19.376141960 +0800 +++ linux-2.6.10/fs/ext3/xattr.h 2005-04-05 12:27:55.527524728 +0800 @@ -70,6 +70,7 @@ extern int ext3_xattr_set_handle(handle_t *, struct inode *, int, const char *,const void *,size_t,int); extern int ext3_xattr_block_set(handle_t *, struct inode *, int, const char *,const void *,size_t,int); +extern int ext3_xattr_get_ea_loc(struct inode *, int, const char *, struct buffer_head **, int *, int *); extern void ext3_xattr_delete_inode(handle_t *, struct inode *); extern void ext3_xattr_put_super(struct super_block *); Index: linux-2.6.10/fs/ext3/extents-in-ea.c =================================================================== --- linux-2.6.10.orig/fs/ext3/extents-in-ea.c 2005-04-05 19:01:49.158500672 +0800 +++ linux-2.6.10/fs/ext3/extents-in-ea.c 2005-04-05 12:27:55.524525184 +0800 @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2003, Cluster File Systems, Inc, info@clusterfs.com + * Written by Alex Tomas + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public Licens + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111- + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int ext3_get_ea_write_access(handle_t *handle, void *buffer) +{ + struct buffer_head *bh = (struct buffer_head *) buffer; + return ext3_journal_get_write_access(handle, bh); +} + +static int ext3_mark_ea_buffer_dirty(handle_t *handle, void *buffer) +{ + struct buffer_head *bh = (struct buffer_head *) buffer; + ext3_journal_dirty_metadata(handle, bh); + return 0; +} + +static struct ext3_extents_helpers ext3_ea_helpers = { + .get_write_access = ext3_get_ea_write_access, + .mark_buffer_dirty = ext3_mark_ea_buffer_dirty, + .mergable = NULL, + .new_block = NULL, + .remove_extent = NULL, + .remove_extent_credits = NULL, +}; + +int ext3_init_tree_in_ea_desc(struct ext3_extents_tree *tree, + struct inode *inode, int name_index, + const char *eaname) +{ + struct buffer_head *bh; + int offset, err, size; + + err = ext3_xattr_get_ea_loc(inode, name_index, eaname, + &bh, &offset, &size); + if (err) + return err; + + EXT_ASSERT(bh); + EXT_ASSERT(size >= sizeof(struct ext3_extent_header) + + sizeof(struct ext3_extent)); + tree->inode = inode; + tree->root = (void *) bh->b_data + offset; + tree->buffer_len = size; + tree->buffer = (void *) bh; + tree->ops = &ext3_ea_helpers; + tree->cex = NULL; /* FIXME: add cache store later */ + return 0; +} + +void ext3_release_tree_in_ea_desc(struct ext3_extents_tree *tree) +{ + struct buffer_head *bh; + + bh = (struct buffer_head *) tree->buffer; + EXT_ASSERT(bh); + brelse(bh); +} + +int ext3_init_tree_in_ea(struct inode *inode, int name_index, + const char *eaname, int size) +{ + struct ext3_extents_tree tree; + handle_t *handle; + char *root; + int err; + + root = kmalloc(size, GFP_USER); + if (!root) + return -ENOMEM; + memset(root, 0, size); + + /* first, create ea to store root of the tree */ + handle = ext3_journal_start(inode, EXT3_ALLOC_NEEDED + 3); + if (IS_ERR(handle)) + return PTR_ERR(handle); + if ((err = ext3_xattr_set(inode, name_index, + eaname, root, size, 0))) + goto out; + if ((err = ext3_init_tree_in_ea_desc(&tree, inode, name_index, eaname))) + goto out; + err = ext3_extent_tree_init(handle, &tree); + ext3_release_tree_in_ea_desc(&tree); +out: + ext3_journal_stop(handle, inode); + kfree(root); + return err; +} + +static int +ext3_ext_in_ea_new_extent(struct ext3_extents_tree *tree, + struct ext3_ext_path *path, + struct ext3_extent *newex, int exist) +{ + struct inode *inode = tree->inode; + handle_t *handle; + int needed, err; + unsigned long tgen; + + if (exist) + return EXT_CONTINUE; + + tgen = EXT_GENERATION(tree); + needed = ext3_ext_calc_credits_for_insert(tree, path); + up(&EXT3_I(inode)->truncate_sem); + handle = ext3_journal_start(tree->inode, needed + 10); + if (IS_ERR(handle)) { + down_write(&EXT3_I(inode)->truncate_sem); + return PTR_ERR(handle); + } + + if (tgen != EXT_GENERATION(tree)) { + /* the tree has changed. so path can be invalid at moment */ + ext3_journal_stop(handle, inode); + down_write(&EXT3_I(inode)->truncate_sem); + return EXT_REPEAT; + } + + down_write(&EXT3_I(inode)->truncate_sem); + + /* insert new extent */ + newex->ee_start = 0; + err = ext3_ext_insert_extent(handle, tree, path, newex); + if (!err) + ext3_journal_stop(handle, tree->inode); + + return err; +} + +int ext3_ext_in_ea_alloc_space(struct inode *inode, int name_index, + const char *eaname, unsigned long from, + unsigned long num) +{ + struct ext3_extents_tree tree; + int err; + + err = ext3_init_tree_in_ea_desc(&tree, inode, name_index, eaname); + if (err == 0) { + down_write(&EXT3_I(inode)->truncate_sem); + err = ext3_ext_walk_space(&tree, from, num, + ext3_ext_in_ea_new_extent); + ext3_release_tree_in_ea_desc(&tree); + up_write(&EXT3_I(inode)->truncate_sem); + } + return err; +} + +int ext3_ext_in_ea_remove_space(struct inode *inode, int name_index, + const char *eaname, unsigned long from, + unsigned long num) +{ + struct ext3_extents_tree tree; + int err; + + err = ext3_init_tree_in_ea_desc(&tree, inode, name_index, eaname); + if (err == 0) { + err = ext3_ext_remove_space(&tree, from, num); + ext3_release_tree_in_ea_desc(&tree); + } + return err; +} + +int ext3_ext_in_ea_presence(struct inode *inode, int name_index, + const char *eaname, unsigned long block) +{ + struct ext3_extents_tree tree; + struct ext3_ext_path *path; + struct ext3_extent *ex; + int err, depth; + + err = ext3_init_tree_in_ea_desc(&tree, inode, name_index, eaname); + if (err) + return err; + + /* find extent for this block */ + path = ext3_ext_find_extent(&tree, block, NULL); + if (IS_ERR(path)) { + err = PTR_ERR(path); + goto out; + } + + depth = EXT_DEPTH(&tree); + ex = path[depth].p_ext; + if (!ex) { + /* there is no extent yet */ + goto out; + } + + if (block >= ex->ee_block && block < ex->ee_block + ex->ee_len) + err = 1; +out: + ext3_release_tree_in_ea_desc(&tree); + return err; +} + Index: linux-2.6.10/fs/ext3/xattr.c =================================================================== --- linux-2.6.10.orig/fs/ext3/xattr.c 2005-04-05 12:26:19.370142872 +0800 +++ linux-2.6.10/fs/ext3/xattr.c 2005-04-05 12:27:55.527524728 +0800 @@ -590,7 +590,8 @@ */ int ext3_xattr_ibody_find(struct inode *inode, int name_index, - const char *name, struct ext3_xattr_entry *rentry, int *free) + const char *name, struct ext3_xattr_entry *rentry, int *free, + struct buffer_head **bh, int *offset) { struct ext3_xattr_entry *last; struct ext3_inode *raw_inode; @@ -637,6 +638,15 @@ name_len == last->e_name_len && !memcmp(name, last->e_name, name_len)) { memcpy(rentry, last, sizeof(struct ext3_xattr_entry)); + if (offset) { + void *voff; + voff = start + le16_to_cpu(last->e_value_offs); + *offset = voff - (void *) iloc.bh->b_data; + } + if (bh) { + get_bh(iloc.bh); + *bh = iloc.bh; + } ret = 0; } else { *free -= EXT3_XATTR_LEN(last->e_name_len); @@ -657,7 +667,8 @@ */ int ext3_xattr_block_find(struct inode *inode, int name_index, const char *name, - struct ext3_xattr_entry *rentry, int *free) + struct ext3_xattr_entry *rentry, int *free, + struct buffer_head **tbh, int *offset) { struct buffer_head *bh = NULL; struct ext3_xattr_entry *entry; @@ -700,6 +711,12 @@ memcmp(name, entry->e_name, name_len) == 0) { memcpy(rentry, entry, sizeof(struct ext3_xattr_entry)); error = 0; + if (offset) + *offset = le16_to_cpu(entry->e_value_offs); + if (tbh) { + get_bh(bh); + *tbh = bh; + } } else { *free -= EXT3_XATTR_LEN(entry->e_name_len); *free -= le32_to_cpu(entry->e_value_size); @@ -894,7 +911,8 @@ down_write(&EXT3_I(inode)->xattr_sem); /* try to find attribute in inode body */ - err = ext3_xattr_ibody_find(inode, name_index, name, &entry, &free1); + err = ext3_xattr_ibody_find(inode, name_index, name, + &entry, &free1, NULL, NULL); if (err == 0) { /* found EA in inode */ found = 1; @@ -903,7 +921,7 @@ /* there is no such attribute in inode body */ /* try to find attribute in dedicated block */ err = ext3_xattr_block_find(inode, name_index, name, - &entry, &free2); + &entry, &free2, NULL, NULL); if (err != 0 && err != -ENOENT) { /* not found EA in block */ goto finish; @@ -960,6 +978,35 @@ return err; } +int ext3_xattr_get_ea_loc(struct inode *inode, int name_index, + const char *name, struct buffer_head **bh, + int *offset, int *size) +{ + int free1 = -1, free2 = -1, err, name_len; + struct ext3_xattr_entry entry; + + ea_idebug(inode, "name=%d.%s", name_index, name); + + if (name == NULL) + return -EINVAL; + name_len = strlen(name); + if (name_len > 255) + return -ERANGE; + + /* try to find attribute in inode body */ + err = ext3_xattr_ibody_find(inode, name_index, name, + &entry, &free1, bh, offset); + if (err == -ENOENT) { + /* there is no such attribute in inode body */ + /* try to find attribute in dedicated block */ + err = ext3_xattr_block_find(inode, name_index, name, + &entry, &free2, bh, offset); + } + if (err == 0 && size) + *size = le32_to_cpu(entry.e_value_size); + return err; +} + /* * ext3_xattr_block_set() * Index: linux-2.6.10/fs/ext3/Makefile =================================================================== --- linux-2.6.10.orig/fs/ext3/Makefile 2005-04-05 12:27:00.597875304 +0800 +++ linux-2.6.10/fs/ext3/Makefile 2005-04-05 12:28:26.989741744 +0800 @@ -7,6 +7,6 @@ ext3-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ ioctl.o namei.o super.o symlink.o hash.o resize.o iopen.o \ extents.o -ext3-$(CONFIG_EXT3_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o +ext3-$(CONFIG_EXT3_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o extents-in-ea.o ext3-$(CONFIG_EXT3_FS_POSIX_ACL) += acl.o ext3-$(CONFIG_EXT3_FS_SECURITY) += xattr_security.o