enable kexec
[linux-2.6.git] / fs / ext3 / inode.c
index f6f61f7..7bc33d5 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/writeback.h>
 #include <linux/mpage.h>
 #include <linux/uio.h>
+#include <linux/vserver/xid.h>
 #include "xattr.h"
 #include "acl.h"
 
@@ -66,6 +67,8 @@ int ext3_forget(handle_t *handle, int is_metadata,
 {
        int err;
 
+       might_sleep();
+
        BUFFER_TRACE(bh, "enter");
 
        jbd_debug(4, "forgetting bh %p: is_metadata = %d, mode %o, "
@@ -176,6 +179,21 @@ static int ext3_journal_test_restart(handle_t *handle, struct inode *inode)
        return ext3_journal_restart(handle, blocks_for_truncate(inode));
 }
 
+static void ext3_truncate_nocheck (struct inode *inode);
+
+/*
+ * Called at each iput()
+ *
+ * The inode may be "bad" if ext3_read_inode() saw an error from
+ * ext3_get_inode(), so we need to check that to avoid freeing random disk
+ * blocks.
+ */
+void ext3_put_inode(struct inode *inode)
+{
+       if (!is_bad_inode(inode))
+               ext3_discard_prealloc(inode);
+}
+
 /*
  * Called at the last iput() if i_nlink is zero.
  */
@@ -199,7 +217,7 @@ void ext3_delete_inode (struct inode * inode)
                handle->h_sync = 1;
        inode->i_size = 0;
        if (inode->i_blocks)
-               ext3_truncate(inode);
+               ext3_truncate_nocheck(inode);
        /*
         * Kill off the orphan record which ext3_truncate created.
         * AKPM: I think this can be inside the above `if'.
@@ -229,12 +247,62 @@ no_delete:
        clear_inode(inode);     /* We must guarantee clearing of inode... */
 }
 
+void ext3_discard_prealloc (struct inode * inode)
+{
+#ifdef EXT3_PREALLOCATE
+       struct ext3_inode_info *ei = EXT3_I(inode);
+       /* Writer: ->i_prealloc* */
+       if (ei->i_prealloc_count) {
+               unsigned short total = ei->i_prealloc_count;
+               unsigned long block = ei->i_prealloc_block;
+               ei->i_prealloc_count = 0;
+               ei->i_prealloc_block = 0;
+               /* Writer: end */
+               ext3_free_blocks (inode, block, total);
+       }
+#endif
+}
+
 static int ext3_alloc_block (handle_t *handle,
                        struct inode * inode, unsigned long goal, int *err)
 {
        unsigned long result;
 
-       result = ext3_new_block (handle, inode, goal, err);
+#ifdef EXT3_PREALLOCATE
+#ifdef EXT3FS_DEBUG
+       static unsigned long alloc_hits, alloc_attempts;
+#endif
+       struct ext3_inode_info *ei = EXT3_I(inode);
+       /* Writer: ->i_prealloc* */
+       if (ei->i_prealloc_count &&
+           (goal == ei->i_prealloc_block ||
+            goal + 1 == ei->i_prealloc_block))
+       {
+               result = ei->i_prealloc_block++;
+               ei->i_prealloc_count--;
+               /* Writer: end */
+               ext3_debug ("preallocation hit (%lu/%lu).\n",
+                           ++alloc_hits, ++alloc_attempts);
+       } else {
+               ext3_discard_prealloc (inode);
+               ext3_debug ("preallocation miss (%lu/%lu).\n",
+                           alloc_hits, ++alloc_attempts);
+               if (S_ISREG(inode->i_mode))
+                       result = ext3_new_block (inode, goal, 
+                                &ei->i_prealloc_count,
+                                &ei->i_prealloc_block, err);
+               else
+                       result = ext3_new_block(inode, goal, NULL, NULL, err);
+               /*
+                * AKPM: this is somewhat sticky.  I'm not surprised it was
+                * disabled in 2.2's ext3.  Need to integrate b_committed_data
+                * guarding with preallocation, if indeed preallocation is
+                * effective.
+                */
+       }
+#else
+       result = ext3_new_block(handle, inode, goal, NULL, NULL, err);
+#endif
        return result;
 }
 
@@ -796,7 +864,7 @@ changed:
 static int ext3_get_block(struct inode *inode, sector_t iblock,
                        struct buffer_head *bh_result, int create)
 {
-       handle_t *handle = 0;
+       handle_t *handle = NULL;
        int ret;
 
        if (create) {
@@ -818,26 +886,42 @@ ext3_direct_io_get_blocks(struct inode *inode, sector_t iblock,
        handle_t *handle = journal_current_handle();
        int ret = 0;
 
-       if (handle && handle->h_buffer_credits <= EXT3_RESERVE_TRANS_BLOCKS) {
+       if (!handle)
+               goto get_block;         /* A read */
+
+       if (handle->h_transaction->t_state == T_LOCKED) {
+               /*
+                * Huge direct-io writes can hold off commits for long
+                * periods of time.  Let this commit run.
+                */
+               ext3_journal_stop(handle);
+               handle = ext3_journal_start(inode, DIO_CREDITS);
+               if (IS_ERR(handle))
+                       ret = PTR_ERR(handle);
+               goto get_block;
+       }
+
+       if (handle->h_buffer_credits <= EXT3_RESERVE_TRANS_BLOCKS) {
                /*
                 * Getting low on buffer credits...
                 */
-               if (!ext3_journal_extend(handle, DIO_CREDITS)) {
+               ret = ext3_journal_extend(handle, DIO_CREDITS);
+               if (ret > 0) {
                        /*
-                        * Couldn't extend the transaction.  Start a new one
+                        * Couldn't extend the transaction.  Start a new one.
                         */
                        ret = ext3_journal_restart(handle, DIO_CREDITS);
                }
        }
+
+get_block:
        if (ret == 0)
                ret = ext3_get_block_handle(handle, inode, iblock,
                                        bh_result, create, 0);
-       if (ret == 0)
-               bh_result->b_size = (1 << inode->i_blkbits);
+       bh_result->b_size = (1 << inode->i_blkbits);
        return ret;
 }
 
-
 /*
  * `handle' can be NULL if create is zero
  */
@@ -902,6 +986,38 @@ struct buffer_head *ext3_bread(handle_t *handle, struct inode * inode,
        bh = ext3_getblk (handle, inode, block, create, err);
        if (!bh)
                return bh;
+#ifdef EXT3_PREALLOCATE
+       /*
+        * If the inode has grown, and this is a directory, then use a few
+        * more of the preallocated blocks to keep directory fragmentation
+        * down.  The preallocated blocks are guaranteed to be contiguous.
+        */
+       if (create &&
+           S_ISDIR(inode->i_mode) &&
+           inode->i_blocks > prev_blocks &&
+           EXT3_HAS_COMPAT_FEATURE(inode->i_sb,
+                                   EXT3_FEATURE_COMPAT_DIR_PREALLOC)) {
+               int i;
+               struct buffer_head *tmp_bh;
+
+               for (i = 1;
+                    EXT3_I(inode)->i_prealloc_count &&
+                    i < EXT3_SB(inode->i_sb)->s_es->s_prealloc_dir_blocks;
+                    i++) {
+                       /*
+                        * ext3_getblk will zero out the contents of the
+                        * directory for us
+                        */
+                       tmp_bh = ext3_getblk(handle, inode,
+                                               block+i, create, err);
+                       if (!tmp_bh) {
+                               brelse (bh);
+                               return 0;
+                       }
+                       brelse (tmp_bh);
+               }
+       }
+#endif
        if (buffer_uptodate(bh))
                return bh;
        ll_rw_block (READ, 1, &bh);
@@ -2020,7 +2136,7 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode,
  * ext3_truncate() run will find them and release them.
  */
 
-void ext3_truncate(struct inode * inode)
+void ext3_truncate_nocheck(struct inode * inode)
 {
        handle_t *handle;
        struct ext3_inode_info *ei = EXT3_I(inode);
@@ -2041,10 +2157,8 @@ void ext3_truncate(struct inode * inode)
                return;
        if (ext3_inode_is_fast_symlink(inode))
                return;
-       if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
-               return;
 
-       ext3_discard_reservation(inode);
+       ext3_discard_prealloc(inode);
 
        /*
         * We have to lock the EOF page here, because lock_page() nests
@@ -2199,11 +2313,9 @@ static unsigned long ext3_get_inode_block(struct super_block *sb,
        unsigned long offset, block;
        struct buffer_head *bh;
        struct ext3_group_desc * gdp;
-       
 
        if ((ino != EXT3_ROOT_INO &&
                ino != EXT3_JOURNAL_INO &&
-               ino != EXT3_RESIZE_INO &&
                ino < EXT3_FIRST_INO(sb)) ||
                ino > le32_to_cpu(
                        EXT3_SB(sb)->s_es->s_inodes_count)) {
@@ -2351,17 +2463,28 @@ has_buffer:
        return 0;
 }
 
+void ext3_truncate(struct inode * inode)
+{
+       if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+               return;
+       ext3_truncate_nocheck(inode);
+}
+
 void ext3_set_inode_flags(struct inode *inode)
 {
        unsigned int flags = EXT3_I(inode)->i_flags;
 
-       inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC);
+       inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_IUNLINK|S_BARRIER|S_NOATIME|S_DIRSYNC);
        if (flags & EXT3_SYNC_FL)
                inode->i_flags |= S_SYNC;
        if (flags & EXT3_APPEND_FL)
                inode->i_flags |= S_APPEND;
        if (flags & EXT3_IMMUTABLE_FL)
                inode->i_flags |= S_IMMUTABLE;
+       if (flags & EXT3_IUNLINK_FL)
+               inode->i_flags |= S_IUNLINK;
+       if (flags & EXT3_BARRIER_FL)
+               inode->i_flags |= S_BARRIER;
        if (flags & EXT3_NOATIME_FL)
                inode->i_flags |= S_NOATIME;
        if (flags & EXT3_DIRSYNC_FL)
@@ -2375,6 +2498,8 @@ void ext3_read_inode(struct inode * inode)
        struct ext3_inode_info *ei = EXT3_I(inode);
        struct buffer_head *bh;
        int block;
+       uid_t uid;
+       gid_t gid;
 
 #ifdef CONFIG_EXT3_FS_POSIX_ACL
        ei->i_acl = EXT3_ACL_NOT_CACHED;
@@ -2385,12 +2510,17 @@ void ext3_read_inode(struct inode * inode)
        bh = iloc.bh;
        raw_inode = ext3_raw_inode(&iloc);
        inode->i_mode = le16_to_cpu(raw_inode->i_mode);
-       inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
-       inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
+       uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
+       gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
        if(!(test_opt (inode->i_sb, NO_UID32))) {
-               inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
-               inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
+               uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
+               gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
        }
+       inode->i_uid = INOXID_UID(XID_TAG(inode), uid, gid);
+       inode->i_gid = INOXID_GID(XID_TAG(inode), uid, gid);
+       inode->i_xid = INOXID_XID(XID_TAG(inode), uid, gid,
+               le16_to_cpu(raw_inode->i_raw_xid));
+
        inode->i_nlink = le16_to_cpu(raw_inode->i_links_count);
        inode->i_size = le32_to_cpu(raw_inode->i_size);
        inode->i_atime.tv_sec = le32_to_cpu(raw_inode->i_atime);
@@ -2439,11 +2569,11 @@ void ext3_read_inode(struct inode * inode)
        }
        ei->i_disksize = inode->i_size;
        inode->i_generation = le32_to_cpu(raw_inode->i_generation);
+#ifdef EXT3_PREALLOCATE
+       ei->i_prealloc_count = 0;
+#endif
        ei->i_block_group = iloc.block_group;
-       ei->i_rsv_window.rsv_start = 0;
-       ei->i_rsv_window.rsv_end= 0;
-       atomic_set(&ei->i_rsv_window.rsv_goal_size, EXT3_DEFAULT_RESERVE_BLOCKS);
-       INIT_LIST_HEAD(&ei->i_rsv_window.rsv_list);
+
        /*
         * NOTE! The in-memory inode i_data array is in little-endian order
         * even on big-endian machines: we do NOT byteswap the block numbers!
@@ -2498,6 +2628,8 @@ static int ext3_do_update_inode(handle_t *handle,
        struct ext3_inode *raw_inode = ext3_raw_inode(iloc);
        struct ext3_inode_info *ei = EXT3_I(inode);
        struct buffer_head *bh = iloc->bh;
+       uid_t uid = XIDINO_UID(XID_TAG(inode), inode->i_uid, inode->i_xid);
+       gid_t gid = XIDINO_GID(XID_TAG(inode), inode->i_gid, inode->i_xid);
        int err = 0, rc, block;
 
        /* For fields not not tracking in the in-memory inode,
@@ -2507,29 +2639,32 @@ static int ext3_do_update_inode(handle_t *handle,
 
        raw_inode->i_mode = cpu_to_le16(inode->i_mode);
        if(!(test_opt(inode->i_sb, NO_UID32))) {
-               raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid));
-               raw_inode->i_gid_low = cpu_to_le16(low_16_bits(inode->i_gid));
+               raw_inode->i_uid_low = cpu_to_le16(low_16_bits(uid));
+               raw_inode->i_gid_low = cpu_to_le16(low_16_bits(gid));
 /*
  * Fix up interoperability with old kernels. Otherwise, old inodes get
  * re-used with the upper 16 bits of the uid/gid intact
  */
                if(!ei->i_dtime) {
                        raw_inode->i_uid_high =
-                               cpu_to_le16(high_16_bits(inode->i_uid));
+                               cpu_to_le16(high_16_bits(uid));
                        raw_inode->i_gid_high =
-                               cpu_to_le16(high_16_bits(inode->i_gid));
+                               cpu_to_le16(high_16_bits(gid));
                } else {
                        raw_inode->i_uid_high = 0;
                        raw_inode->i_gid_high = 0;
                }
        } else {
                raw_inode->i_uid_low =
-                       cpu_to_le16(fs_high2lowuid(inode->i_uid));
+                       cpu_to_le16(fs_high2lowuid(uid));
                raw_inode->i_gid_low =
-                       cpu_to_le16(fs_high2lowgid(inode->i_gid));
+                       cpu_to_le16(fs_high2lowgid(gid));
                raw_inode->i_uid_high = 0;
                raw_inode->i_gid_high = 0;
        }
+#ifdef CONFIG_INOXID_GID32
+       raw_inode->i_raw_xid = cpu_to_le16(inode->i_xid);
+#endif
        raw_inode->i_links_count = cpu_to_le16(inode->i_nlink);
        raw_inode->i_size = cpu_to_le32(ei->i_disksize);
        raw_inode->i_atime = cpu_to_le32(inode->i_atime.tv_sec);
@@ -2651,6 +2786,44 @@ void ext3_write_inode(struct inode *inode, int wait)
        ext3_force_commit(inode->i_sb);
 }
 
+int ext3_setattr_flags(struct inode *inode, unsigned int flags)
+{
+       unsigned int oldflags, newflags;
+       int err = 0;
+
+       oldflags = EXT3_I(inode)->i_flags;
+       newflags = oldflags &
+               ~(EXT3_IMMUTABLE_FL | EXT3_IUNLINK_FL | EXT3_BARRIER_FL);       
+       if (flags & ATTR_FLAG_IMMUTABLE)
+               newflags |= EXT3_IMMUTABLE_FL;
+       if (flags & ATTR_FLAG_IUNLINK)
+               newflags |= EXT3_IUNLINK_FL;
+       if (flags & ATTR_FLAG_BARRIER)
+               newflags |= EXT3_BARRIER_FL;
+
+       if (oldflags ^ newflags) {
+               handle_t *handle;
+               struct ext3_iloc iloc;
+
+               handle = ext3_journal_start(inode, 1);
+               if (IS_ERR(handle))
+                       return PTR_ERR(handle);
+               if (IS_SYNC(inode))
+                       handle->h_sync = 1;
+               err = ext3_reserve_inode_write(handle, inode, &iloc);
+               if (err)
+                       goto flags_err;
+               
+               EXT3_I(inode)->i_flags = newflags;
+               inode->i_ctime = CURRENT_TIME;
+
+               err = ext3_mark_iloc_dirty(handle, inode, &iloc);
+       flags_err:
+               ext3_journal_stop(handle);
+       }
+       return err;
+}
+
 /*
  * ext3_setattr()
  *
@@ -2679,7 +2852,8 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr)
                return error;
 
        if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
-               (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
+               (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid) ||
+               (ia_valid & ATTR_XID && attr->ia_xid != inode->i_xid)) {
                handle_t *handle;
 
                /* (user+group)*(old+new) structure, inode write (sb,
@@ -2700,6 +2874,10 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr)
                        inode->i_uid = attr->ia_uid;
                if (attr->ia_valid & ATTR_GID)
                        inode->i_gid = attr->ia_gid;
+               if ((attr->ia_valid & ATTR_XID)
+                       && inode->i_sb
+                       && (inode->i_sb->s_flags & MS_TAGXID))
+                       inode->i_xid = attr->ia_xid;
                error = ext3_mark_inode_dirty(handle, inode);
                ext3_journal_stop(handle);
        }
@@ -2722,6 +2900,12 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr)
                ext3_journal_stop(handle);
        }
 
+       if (ia_valid & ATTR_ATTR_FLAG) {
+               rc = ext3_setattr_flags(inode, attr->ia_attr_flags);
+               if (!error)
+                       error = rc;
+       }
+
        rc = inode_setattr(inode, attr);
 
        /* If inode_setattr's call to ext3_truncate failed to get a
@@ -2857,6 +3041,7 @@ int ext3_mark_inode_dirty(handle_t *handle, struct inode *inode)
        struct ext3_iloc iloc;
        int err;
 
+       might_sleep();
        err = ext3_reserve_inode_write(handle, inode, &iloc);
        if (!err)
                err = ext3_mark_iloc_dirty(handle, inode, &iloc);