Merge branch 'for-2.6.35' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
[safe/jmp/linux-2.6] / fs / ext4 / xattr.c
index 726716b..b4c5aa8 100644 (file)
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
-#include <linux/ext4_jbd2.h>
-#include <linux/ext4_fs.h>
 #include <linux/mbcache.h>
 #include <linux/quotaops.h>
 #include <linux/rwsem.h>
+#include "ext4_jbd2.h"
+#include "ext4.h"
 #include "xattr.h"
 #include "acl.h"
 
@@ -92,17 +92,19 @@ static struct buffer_head *ext4_xattr_cache_find(struct inode *,
                                                 struct mb_cache_entry **);
 static void ext4_xattr_rehash(struct ext4_xattr_header *,
                              struct ext4_xattr_entry *);
+static int ext4_xattr_list(struct dentry *dentry, char *buffer,
+                          size_t buffer_size);
 
 static struct mb_cache *ext4_xattr_cache;
 
 static struct xattr_handler *ext4_xattr_handler_map[] = {
        [EXT4_XATTR_INDEX_USER]              = &ext4_xattr_user_handler,
-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+#ifdef CONFIG_EXT4_FS_POSIX_ACL
        [EXT4_XATTR_INDEX_POSIX_ACL_ACCESS]  = &ext4_xattr_acl_access_handler,
        [EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT] = &ext4_xattr_acl_default_handler,
 #endif
        [EXT4_XATTR_INDEX_TRUSTED]           = &ext4_xattr_trusted_handler,
-#ifdef CONFIG_EXT4DEV_FS_SECURITY
+#ifdef CONFIG_EXT4_FS_SECURITY
        [EXT4_XATTR_INDEX_SECURITY]          = &ext4_xattr_security_handler,
 #endif
 };
@@ -110,11 +112,11 @@ static struct xattr_handler *ext4_xattr_handler_map[] = {
 struct xattr_handler *ext4_xattr_handlers[] = {
        &ext4_xattr_user_handler,
        &ext4_xattr_trusted_handler,
-#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+#ifdef CONFIG_EXT4_FS_POSIX_ACL
        &ext4_xattr_acl_access_handler,
        &ext4_xattr_acl_default_handler,
 #endif
-#ifdef CONFIG_EXT4DEV_FS_SECURITY
+#ifdef CONFIG_EXT4_FS_SECURITY
        &ext4_xattr_security_handler,
 #endif
        NULL
@@ -138,7 +140,7 @@ ext4_xattr_handler(int name_index)
 ssize_t
 ext4_listxattr(struct dentry *dentry, char *buffer, size_t size)
 {
-       return ext4_xattr_list(dentry->d_inode, buffer, size);
+       return ext4_xattr_list(dentry, buffer, size);
 }
 
 static int
@@ -225,7 +227,8 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name,
        ea_bdebug(bh, "b_count=%d, refcount=%d",
                atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));
        if (ext4_xattr_check_block(bh)) {
-bad_block:     ext4_error(inode->i_sb, __FUNCTION__,
+bad_block:
+               ext4_error(inode->i_sb,
                           "inode %lu: bad block %llu", inode->i_ino,
                           EXT4_I(inode)->i_file_acl);
                error = -EIO;
@@ -265,7 +268,7 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
        void *end;
        int error;
 
-       if (!(EXT4_I(inode)->i_state & EXT4_STATE_XATTR))
+       if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR))
                return -ENODATA;
        error = ext4_get_inode_loc(inode, &iloc);
        if (error)
@@ -323,7 +326,7 @@ ext4_xattr_get(struct inode *inode, int name_index, const char *name,
 }
 
 static int
-ext4_xattr_list_entries(struct inode *inode, struct ext4_xattr_entry *entry,
+ext4_xattr_list_entries(struct dentry *dentry, struct ext4_xattr_entry *entry,
                        char *buffer, size_t buffer_size)
 {
        size_t rest = buffer_size;
@@ -333,9 +336,10 @@ ext4_xattr_list_entries(struct inode *inode, struct ext4_xattr_entry *entry,
                        ext4_xattr_handler(entry->e_name_index);
 
                if (handler) {
-                       size_t size = handler->list(inode, buffer, rest,
+                       size_t size = handler->list(dentry, buffer, rest,
                                                    entry->e_name,
-                                                   entry->e_name_len);
+                                                   entry->e_name_len,
+                                                   handler->flags);
                        if (buffer) {
                                if (size > rest)
                                        return -ERANGE;
@@ -348,8 +352,9 @@ ext4_xattr_list_entries(struct inode *inode, struct ext4_xattr_entry *entry,
 }
 
 static int
-ext4_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size)
+ext4_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size)
 {
+       struct inode *inode = dentry->d_inode;
        struct buffer_head *bh = NULL;
        int error;
 
@@ -367,14 +372,14 @@ ext4_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size)
        ea_bdebug(bh, "b_count=%d, refcount=%d",
                atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));
        if (ext4_xattr_check_block(bh)) {
-               ext4_error(inode->i_sb, __FUNCTION__,
+               ext4_error(inode->i_sb,
                           "inode %lu: bad block %llu", inode->i_ino,
                           EXT4_I(inode)->i_file_acl);
                error = -EIO;
                goto cleanup;
        }
        ext4_xattr_cache_insert(bh);
-       error = ext4_xattr_list_entries(inode, BFIRST(bh), buffer, buffer_size);
+       error = ext4_xattr_list_entries(dentry, BFIRST(bh), buffer, buffer_size);
 
 cleanup:
        brelse(bh);
@@ -383,15 +388,16 @@ cleanup:
 }
 
 static int
-ext4_xattr_ibody_list(struct inode *inode, char *buffer, size_t buffer_size)
+ext4_xattr_ibody_list(struct dentry *dentry, char *buffer, size_t buffer_size)
 {
+       struct inode *inode = dentry->d_inode;
        struct ext4_xattr_ibody_header *header;
        struct ext4_inode *raw_inode;
        struct ext4_iloc iloc;
        void *end;
        int error;
 
-       if (!(EXT4_I(inode)->i_state & EXT4_STATE_XATTR))
+       if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR))
                return 0;
        error = ext4_get_inode_loc(inode, &iloc);
        if (error)
@@ -402,7 +408,7 @@ ext4_xattr_ibody_list(struct inode *inode, char *buffer, size_t buffer_size)
        error = ext4_xattr_check_names(IFIRST(header), end);
        if (error)
                goto cleanup;
-       error = ext4_xattr_list_entries(inode, IFIRST(header),
+       error = ext4_xattr_list_entries(dentry, IFIRST(header),
                                        buffer, buffer_size);
 
 cleanup:
@@ -420,13 +426,13 @@ cleanup:
  * Returns a negative error number on failure, or the number of bytes
  * used / required on success.
  */
-int
-ext4_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
+static int
+ext4_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size)
 {
        int i_error, b_error;
 
-       down_read(&EXT4_I(inode)->xattr_sem);
-       i_error = ext4_xattr_ibody_list(inode, buffer, buffer_size);
+       down_read(&EXT4_I(dentry->d_inode)->xattr_sem);
+       i_error = ext4_xattr_ibody_list(dentry, buffer, buffer_size);
        if (i_error < 0) {
                b_error = 0;
        } else {
@@ -434,11 +440,11 @@ ext4_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
                        buffer += i_error;
                        buffer_size -= i_error;
                }
-               b_error = ext4_xattr_block_list(inode, buffer, buffer_size);
+               b_error = ext4_xattr_block_list(dentry, buffer, buffer_size);
                if (b_error < 0)
                        i_error = 0;
        }
-       up_read(&EXT4_I(inode)->xattr_sem);
+       up_read(&EXT4_I(dentry->d_inode)->xattr_sem);
        return i_error + b_error;
 }
 
@@ -455,7 +461,7 @@ static void ext4_xattr_update_super_block(handle_t *handle,
        if (ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh) == 0) {
                EXT4_SET_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_EXT_ATTR);
                sb->s_dirt = 1;
-               ext4_journal_dirty_metadata(handle, EXT4_SB(sb)->s_sbh);
+               ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh);
        }
 }
 
@@ -480,15 +486,16 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode,
                ea_bdebug(bh, "refcount now=0; freeing");
                if (ce)
                        mb_cache_entry_free(ce);
-               ext4_free_blocks(handle, inode, bh->b_blocknr, 1, 1);
                get_bh(bh);
-               ext4_forget(handle, 1, inode, bh, bh->b_blocknr);
+               ext4_free_blocks(handle, inode, bh, 0, 1,
+                                EXT4_FREE_BLOCKS_METADATA |
+                                EXT4_FREE_BLOCKS_FORGET);
        } else {
                le32_add_cpu(&BHDR(bh)->h_refcount, -1);
-               error = ext4_journal_dirty_metadata(handle, bh);
+               error = ext4_handle_dirty_metadata(handle, inode, bh);
                if (IS_SYNC(inode))
-                       handle->h_sync = 1;
-               DQUOT_FREE_BLOCK(inode, 1);
+                       ext4_handle_sync(handle);
+               dquot_free_block(inode, 1);
                ea_bdebug(bh, "refcount now=%d; releasing",
                          le32_to_cpu(BHDR(bh)->h_refcount));
                if (ce)
@@ -659,9 +666,8 @@ ext4_xattr_block_find(struct inode *inode, struct ext4_xattr_info *i,
                        atomic_read(&(bs->bh->b_count)),
                        le32_to_cpu(BHDR(bs->bh)->h_refcount));
                if (ext4_xattr_check_block(bs->bh)) {
-                       ext4_error(sb, __FUNCTION__,
-                               "inode %lu: bad block %llu", inode->i_ino,
-                               EXT4_I(inode)->i_file_acl);
+                       ext4_error(sb, "inode %lu: bad block %llu",
+                                  inode->i_ino, EXT4_I(inode)->i_file_acl);
                        error = -EIO;
                        goto cleanup;
                }
@@ -722,8 +728,9 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
                        if (error == -EIO)
                                goto bad_block;
                        if (!error)
-                               error = ext4_journal_dirty_metadata(handle,
-                                                                   bs->bh);
+                               error = ext4_handle_dirty_metadata(handle,
+                                                                  inode,
+                                                                  bs->bh);
                        if (error)
                                goto cleanup;
                        goto inserted;
@@ -737,7 +744,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
                                ce = NULL;
                        }
                        ea_bdebug(bs->bh, "cloning");
-                       s->base = kmalloc(bs->bh->b_size, GFP_KERNEL);
+                       s->base = kmalloc(bs->bh->b_size, GFP_NOFS);
                        error = -ENOMEM;
                        if (s->base == NULL)
                                goto cleanup;
@@ -749,7 +756,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
                }
        } else {
                /* Allocate a buffer where we construct the new block. */
-               s->base = kzalloc(sb->s_blocksize, GFP_KERNEL);
+               s->base = kzalloc(sb->s_blocksize, GFP_NOFS);
                /* assert(header == s->base) */
                error = -ENOMEM;
                if (s->base == NULL)
@@ -780,8 +787,8 @@ inserted:
                        else {
                                /* The old block is released after updating
                                   the inode. */
-                               error = -EDQUOT;
-                               if (DQUOT_ALLOC_BLOCK(inode, 1))
+                               error = dquot_alloc_block(inode, 1);
+                               if (error)
                                        goto cleanup;
                                error = ext4_journal_get_write_access(handle,
                                                                      new_bh);
@@ -792,8 +799,9 @@ inserted:
                                ea_bdebug(new_bh, "reusing; refcount now=%d",
                                        le32_to_cpu(BHDR(new_bh)->h_refcount));
                                unlock_buffer(new_bh);
-                               error = ext4_journal_dirty_metadata(handle,
-                                                                   new_bh);
+                               error = ext4_handle_dirty_metadata(handle,
+                                                                  inode,
+                                                                  new_bh);
                                if (error)
                                        goto cleanup_dquot;
                        }
@@ -806,20 +814,30 @@ inserted:
                        get_bh(new_bh);
                } else {
                        /* We need to allocate a new block */
-                       ext4_fsblk_t goal = le32_to_cpu(
-                                       EXT4_SB(sb)->s_es->s_first_data_block) +
-                               (ext4_fsblk_t)EXT4_I(inode)->i_block_group *
-                               EXT4_BLOCKS_PER_GROUP(sb);
-                       ext4_fsblk_t block = ext4_new_block(handle, inode,
-                                                       goal, &error);
+                       ext4_fsblk_t goal, block;
+
+                       goal = ext4_group_first_block_no(sb,
+                                               EXT4_I(inode)->i_block_group);
+
+                       /* non-extent files can't have physical blocks past 2^32 */
+                       if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL))
+                               goal = goal & EXT4_MAX_BLOCK_FILE_PHYS;
+
+                       block = ext4_new_meta_blocks(handle, inode,
+                                                 goal, NULL, &error);
                        if (error)
                                goto cleanup;
+
+                       if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL))
+                               BUG_ON(block > EXT4_MAX_BLOCK_FILE_PHYS);
+
                        ea_idebug(inode, "creating block %d", block);
 
                        new_bh = sb_getblk(sb, block);
                        if (!new_bh) {
 getblk_failed:
-                               ext4_free_blocks(handle, inode, block, 1, 1);
+                               ext4_free_blocks(handle, inode, 0, block, 1,
+                                                EXT4_FREE_BLOCKS_METADATA);
                                error = -EIO;
                                goto cleanup;
                        }
@@ -833,7 +851,8 @@ getblk_failed:
                        set_buffer_uptodate(new_bh);
                        unlock_buffer(new_bh);
                        ext4_xattr_cache_insert(new_bh);
-                       error = ext4_journal_dirty_metadata(handle, new_bh);
+                       error = ext4_handle_dirty_metadata(handle,
+                                                          inode, new_bh);
                        if (error)
                                goto cleanup;
                }
@@ -857,13 +876,12 @@ cleanup:
        return error;
 
 cleanup_dquot:
-       DQUOT_FREE_BLOCK(inode, 1);
+       dquot_free_block(inode, 1);
        goto cleanup;
 
 bad_block:
-       ext4_error(inode->i_sb, __FUNCTION__,
-                  "inode %lu: bad block %llu", inode->i_ino,
-                  EXT4_I(inode)->i_file_acl);
+       ext4_error(inode->i_sb, "inode %lu: bad block %llu",
+                  inode->i_ino, EXT4_I(inode)->i_file_acl);
        goto cleanup;
 
 #undef header
@@ -889,7 +907,7 @@ ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i,
        is->s.base = is->s.first = IFIRST(header);
        is->s.here = is->s.first;
        is->s.end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
-       if (EXT4_I(inode)->i_state & EXT4_STATE_XATTR) {
+       if (ext4_test_inode_state(inode, EXT4_STATE_XATTR)) {
                error = ext4_xattr_check_names(IFIRST(header), is->s.end);
                if (error)
                        return error;
@@ -921,10 +939,10 @@ ext4_xattr_ibody_set(handle_t *handle, struct inode *inode,
        header = IHDR(inode, ext4_raw_inode(&is->iloc));
        if (!IS_LAST_ENTRY(s->first)) {
                header->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC);
-               EXT4_I(inode)->i_state |= EXT4_STATE_XATTR;
+               ext4_set_inode_state(inode, EXT4_STATE_XATTR);
        } else {
                header->h_magic = cpu_to_le32(0);
-               EXT4_I(inode)->i_state &= ~EXT4_STATE_XATTR;
+               ext4_clear_inode_state(inode, EXT4_STATE_XATTR);
        }
        return 0;
 }
@@ -959,6 +977,7 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
        struct ext4_xattr_block_find bs = {
                .s = { .not_found = -ENODATA, },
        };
+       unsigned long no_expand;
        int error;
 
        if (!name)
@@ -966,14 +985,21 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
        if (strlen(name) > 255)
                return -ERANGE;
        down_write(&EXT4_I(inode)->xattr_sem);
+       no_expand = ext4_test_inode_state(inode, EXT4_STATE_NO_EXPAND);
+       ext4_set_inode_state(inode, EXT4_STATE_NO_EXPAND);
+
        error = ext4_get_inode_loc(inode, &is.iloc);
        if (error)
                goto cleanup;
 
-       if (EXT4_I(inode)->i_state & EXT4_STATE_NEW) {
+       error = ext4_journal_get_write_access(handle, is.iloc.bh);
+       if (error)
+               goto cleanup;
+
+       if (ext4_test_inode_state(inode, EXT4_STATE_NEW)) {
                struct ext4_inode *raw_inode = ext4_raw_inode(&is.iloc);
                memset(raw_inode, 0, EXT4_SB(inode->i_sb)->s_inode_size);
-               EXT4_I(inode)->i_state &= ~EXT4_STATE_NEW;
+               ext4_clear_inode_state(inode, EXT4_STATE_NEW);
        }
 
        error = ext4_xattr_ibody_find(inode, &i, &is);
@@ -995,9 +1021,6 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
                if (flags & XATTR_CREATE)
                        goto cleanup;
        }
-       error = ext4_journal_get_write_access(handle, is.iloc.bh);
-       if (error)
-               goto cleanup;
        if (!value) {
                if (!is.s.not_found)
                        error = ext4_xattr_ibody_set(handle, inode, &i, &is);
@@ -1009,6 +1032,11 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
                        i.value = NULL;
                        error = ext4_xattr_block_set(handle, inode, &i, &bs);
                } else if (error == -ENOSPC) {
+                       if (EXT4_I(inode)->i_file_acl && !bs.s.base) {
+                               error = ext4_xattr_block_find(inode, &i, &bs);
+                               if (error)
+                                       goto cleanup;
+                       }
                        error = ext4_xattr_block_set(handle, inode, &i, &bs);
                        if (error)
                                goto cleanup;
@@ -1023,7 +1051,7 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
                ext4_xattr_update_super_block(handle, inode->i_sb);
                inode->i_ctime = ext4_current_time(inode);
                if (!value)
-                       EXT4_I(inode)->i_state &= ~EXT4_STATE_NO_EXPAND;
+                       ext4_clear_inode_state(inode, EXT4_STATE_NO_EXPAND);
                error = ext4_mark_iloc_dirty(handle, inode, &is.iloc);
                /*
                 * The bh is consumed by ext4_mark_iloc_dirty, even with
@@ -1031,12 +1059,14 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
                 */
                is.iloc.bh = NULL;
                if (IS_SYNC(inode))
-                       handle->h_sync = 1;
+                       ext4_handle_sync(handle);
        }
 
 cleanup:
        brelse(is.iloc.bh);
        brelse(bs.bh);
+       if (no_expand == 0)
+               ext4_clear_inode_state(inode, EXT4_STATE_NO_EXPAND);
        up_write(&EXT4_I(inode)->xattr_sem);
        return error;
 }
@@ -1164,9 +1194,8 @@ retry:
                if (!bh)
                        goto cleanup;
                if (ext4_xattr_check_block(bh)) {
-                       ext4_error(inode->i_sb, __FUNCTION__,
-                               "inode %lu: bad block %llu", inode->i_ino,
-                               EXT4_I(inode)->i_file_acl);
+                       ext4_error(inode->i_sb, "inode %lu: bad block %llu",
+                                  inode->i_ino, EXT4_I(inode)->i_file_acl);
                        error = -EIO;
                        goto cleanup;
                }
@@ -1271,6 +1300,8 @@ retry:
 
                /* Remove the chosen entry from the inode */
                error = ext4_xattr_ibody_set(handle, inode, &i, is);
+               if (error)
+                       goto cleanup;
 
                entry = IFIRST(header);
                if (entry_size + EXT4_XATTR_SIZE(size) >= new_extra_isize)
@@ -1301,6 +1332,8 @@ retry:
                        goto cleanup;
                kfree(b_entry_name);
                kfree(buffer);
+               b_entry_name = NULL;
+               buffer = NULL;
                brelse(is->iloc.bh);
                kfree(is);
                kfree(bs);
@@ -1339,16 +1372,14 @@ ext4_xattr_delete_inode(handle_t *handle, struct inode *inode)
                goto cleanup;
        bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl);
        if (!bh) {
-               ext4_error(inode->i_sb, __FUNCTION__,
-                       "inode %lu: block %llu read error", inode->i_ino,
-                       EXT4_I(inode)->i_file_acl);
+               ext4_error(inode->i_sb, "inode %lu: block %llu read error",
+                          inode->i_ino, EXT4_I(inode)->i_file_acl);
                goto cleanup;
        }
        if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) ||
            BHDR(bh)->h_blocks != cpu_to_le32(1)) {
-               ext4_error(inode->i_sb, __FUNCTION__,
-                       "inode %lu: bad block %llu", inode->i_ino,
-                       EXT4_I(inode)->i_file_acl);
+               ext4_error(inode->i_sb, "inode %lu: bad block %llu",
+                          inode->i_ino, EXT4_I(inode)->i_file_acl);
                goto cleanup;
        }
        ext4_xattr_release_block(handle, inode, bh);
@@ -1473,7 +1504,7 @@ again:
                }
                bh = sb_bread(inode->i_sb, ce->e_block);
                if (!bh) {
-                       ext4_error(inode->i_sb, __FUNCTION__,
+                       ext4_error(inode->i_sb,
                                "inode %lu: block %lu read error",
                                inode->i_ino, (unsigned long) ce->e_block);
                } else if (le32_to_cpu(BHDR(bh)->h_refcount) >=
@@ -1507,7 +1538,7 @@ static inline void ext4_xattr_hash_entry(struct ext4_xattr_header *header,
        char *name = entry->e_name;
        int n;
 
-       for (n=0; n < entry->e_name_len; n++) {
+       for (n = 0; n < entry->e_name_len; n++) {
                hash = (hash << NAME_HASH_SHIFT) ^
                       (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^
                       *name++;