patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / fs / ext3 / inode.c
index b76259e..ebfa3b0 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"
 
@@ -189,6 +190,8 @@ void ext3_put_inode(struct inode *inode)
                ext3_discard_prealloc(inode);
 }
 
+static void ext3_truncate_nocheck (struct inode *inode);
+
 /*
  * Called at the last iput() if i_nlink is zero.
  */
@@ -205,8 +208,6 @@ void ext3_delete_inode (struct inode * inode)
                 * need to make sure that the in-core orphan linked list
                 * is properly cleaned up. */
                ext3_orphan_del(NULL, inode);
-
-               ext3_std_error(inode->i_sb, PTR_ERR(handle));
                goto no_delete;
        }
 
@@ -214,7 +215,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'.
@@ -811,6 +812,7 @@ out:
        if (err == -EAGAIN)
                goto changed;
 
+       goal = 0;
        down(&ei->truncate_sem);
        if (ext3_find_goal(inode, iblock, chain, partial, &goal) < 0) {
                up(&ei->truncate_sem);
@@ -1081,15 +1083,28 @@ static int ext3_prepare_write(struct file *file, struct page *page,
        struct inode *inode = page->mapping->host;
        int ret, needed_blocks = ext3_writepage_trans_blocks(inode);
        handle_t *handle;
+       int tried_commit = 0;
 
+retry:
        handle = ext3_journal_start(inode, needed_blocks);
        if (IS_ERR(handle)) {
                ret = PTR_ERR(handle);
                goto out;
        }
        ret = block_prepare_write(page, from, to, ext3_get_block);
-       if (ret != 0)
-               goto prepare_write_failed;
+       if (ret) {
+               if (ret != -ENOSPC || tried_commit)
+                       goto prepare_write_failed;
+               /*
+                * It could be that there _is_ free space, but it's all tied up
+                * in uncommitted bitmaps.  So force a commit here, which makes
+                * those blocks allocatable and try again.
+                */
+               tried_commit = 1;
+               handle->h_sync = 1;
+               ext3_journal_stop(handle);
+               goto retry;
+       }
 
        if (ext3_should_journal_data(inode)) {
                ret = walk_page_buffers(handle, page_buffers(page),
@@ -2112,7 +2127,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);
@@ -2133,8 +2148,6 @@ 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_prealloc(inode);
 
@@ -2441,6 +2454,13 @@ 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;
@@ -2452,6 +2472,10 @@ void ext3_set_inode_flags(struct inode *inode)
                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)
@@ -2465,6 +2489,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;
@@ -2475,12 +2501,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(uid, gid);
+       inode->i_gid = INOXID_GID(uid, gid);
+       if (inode->i_sb->s_flags & MS_TAGXID)
+               inode->i_xid = INOXID_XID(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);
@@ -2588,6 +2619,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(inode->i_uid, inode->i_xid);
+       gid_t gid = XIDINO_GID(inode->i_gid, inode->i_xid);
        int err = 0, rc, block;
 
        /* For fields not not tracking in the in-memory inode,
@@ -2597,29 +2630,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);
@@ -2741,6 +2777,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()
  *
@@ -2769,7 +2843,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,
@@ -2790,6 +2865,8 @@ 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_xid = attr->ia_xid;
                error = ext3_mark_inode_dirty(handle, inode);
                ext3_journal_stop(handle);
        }
@@ -2812,6 +2889,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