Merge to Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.13-vs2...
[linux-2.6.git] / fs / ext2 / inode.c
index 9b8aeac..c6a0128 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/vserver/xid.h>
 #include "ext2.h"
 #include "acl.h"
+#include "xip.h"
 
 MODULE_AUTHOR("Remy Card and others");
 MODULE_DESCRIPTION("Second Extended Filesystem");
@@ -66,13 +67,13 @@ void ext2_put_inode(struct inode *inode)
                ext2_discard_prealloc(inode);
 }
 
-static void ext2_truncate_nocheck (struct inode * inode);
-
 /*
  * Called at the last iput() if i_nlink is zero.
  */
 void ext2_delete_inode (struct inode * inode)
 {
+       truncate_inode_pages(&inode->i_data, 0);
+
        if (is_bad_inode(inode))
                goto no_delete;
        EXT2_I(inode)->i_dtime  = get_seconds();
@@ -81,7 +82,7 @@ void ext2_delete_inode (struct inode * inode)
 
        inode->i_size = 0;
        if (inode->i_blocks)
-               ext2_truncate_nocheck(inode);
+               ext2_truncate (inode);
        ext2_free_inode (inode);
 
        return;
@@ -136,7 +137,7 @@ static int ext2_alloc_block (struct inode * inode, unsigned long goal, int *err)
                                 &ei->i_prealloc_count,
                                 &ei->i_prealloc_block, err);
                else
-                       result = ext2_new_block (inode, goal, 0, 0, err);
+                       result = ext2_new_block(inode, goal, NULL, NULL, err);
        }
 #else
        result = ext2_new_block (inode, goal, 0, 0, err);
@@ -145,12 +146,12 @@ static int ext2_alloc_block (struct inode * inode, unsigned long goal, int *err)
 }
 
 typedef struct {
-       u32     *p;
-       u32     key;
+       __le32  *p;
+       __le32  key;
        struct buffer_head *bh;
 } Indirect;
 
-static inline void add_chain(Indirect *p, struct buffer_head *bh, u32 *v)
+static inline void add_chain(Indirect *p, struct buffer_head *bh, __le32 *v)
 {
        p->key = *(p->p = v);
        p->bh = bh;
@@ -283,7 +284,7 @@ static Indirect *ext2_get_branch(struct inode *inode,
                read_lock(&EXT2_I(inode)->i_meta_lock);
                if (!verify_chain(chain, p))
                        goto changed;
-               add_chain(++p, bh, (u32*)bh->b_data + *++offsets);
+               add_chain(++p, bh, (__le32*)bh->b_data + *++offsets);
                read_unlock(&EXT2_I(inode)->i_meta_lock);
                if (!p->key)
                        goto no_block;
@@ -324,8 +325,8 @@ no_block:
 static unsigned long ext2_find_near(struct inode *inode, Indirect *ind)
 {
        struct ext2_inode_info *ei = EXT2_I(inode);
-       u32 *start = ind->bh ? (u32*) ind->bh->b_data : ei->i_data;
-       u32 *p;
+       __le32 *start = ind->bh ? (__le32 *) ind->bh->b_data : ei->i_data;
+       __le32 *p;
        unsigned long bg_start;
        unsigned long colour;
 
@@ -370,7 +371,7 @@ static inline int ext2_find_goal(struct inode *inode,
 {
        struct ext2_inode_info *ei = EXT2_I(inode);
        write_lock(&ei->i_meta_lock);
-       if (block == ei->i_next_alloc_block + 1) {
+       if ((block == ei->i_next_alloc_block + 1) && ei->i_next_alloc_goal) {
                ei->i_next_alloc_block++;
                ei->i_next_alloc_goal++;
        } 
@@ -440,10 +441,14 @@ static int ext2_alloc_branch(struct inode *inode,
                 * the pointer to new one, then send parent to disk.
                 */
                bh = sb_getblk(inode->i_sb, parent);
+               if (!bh) {
+                       err = -EIO;
+                       break;
+               }
                lock_buffer(bh);
                memset(bh->b_data, 0, blocksize);
                branch[n].bh = bh;
-               branch[n].p = (u32*) bh->b_data + offsets[n];
+               branch[n].p = (__le32 *) bh->b_data + offsets[n];
                *branch[n].p = branch[n].key;
                set_buffer_uptodate(bh);
                unlock_buffer(bh);
@@ -509,7 +514,7 @@ static inline int ext2_splice_branch(struct inode *inode,
 
        /* We are done with atomic stuff, now do the rest of housekeeping */
 
-       inode->i_ctime = CURRENT_TIME;
+       inode->i_ctime = CURRENT_TIME_SEC;
 
        /* had we spliced it onto indirect block? */
        if (where->bh)
@@ -540,7 +545,7 @@ changed:
  * reachable from inode.
  */
 
-static int ext2_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create)
+int ext2_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create)
 {
        int err = -EIO;
        int offsets[4];
@@ -587,6 +592,7 @@ out:
        if (err == -EAGAIN)
                goto changed;
 
+       goal = 0;
        if (ext2_find_goal(inode, iblock, chain, partial, &goal) < 0)
                goto changed;
 
@@ -596,6 +602,16 @@ out:
        if (err)
                goto cleanup;
 
+       if (ext2_use_xip(inode->i_sb)) {
+               /*
+                * we need to clear the block
+                */
+               err = ext2_clear_xip_target (inode,
+                       le32_to_cpu(chain[depth-1].key));
+               if (err)
+                       goto cleanup;
+       }
+
        if (ext2_splice_branch(inode, iblock, chain, partial, left) < 0)
                goto changed;
 
@@ -641,21 +657,15 @@ ext2_nobh_prepare_write(struct file *file, struct page *page,
        return nobh_prepare_write(page,from,to,ext2_get_block);
 }
 
-static sector_t ext2_bmap(struct address_space *mapping, sector_t block)
+static int ext2_nobh_writepage(struct page *page,
+                       struct writeback_control *wbc)
 {
-       return generic_block_bmap(mapping,block,ext2_get_block);
+       return nobh_writepage(page, ext2_get_block, wbc);
 }
 
-static int
-ext2_get_blocks(struct inode *inode, sector_t iblock, unsigned long max_blocks,
-                       struct buffer_head *bh_result, int create)
+static sector_t ext2_bmap(struct address_space *mapping, sector_t block)
 {
-       int ret;
-
-       ret = ext2_get_block(inode, iblock, bh_result, create);
-       if (ret == 0)
-               bh_result->b_size = (1 << inode->i_blkbits);
-       return ret;
+       return generic_block_bmap(mapping,block,ext2_get_block);
 }
 
 static ssize_t
@@ -666,7 +676,7 @@ ext2_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
        struct inode *inode = file->f_mapping->host;
 
        return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
-                               offset, nr_segs, ext2_get_blocks, NULL);
+                               offset, nr_segs, ext2_get_block, NULL);
 }
 
 static int
@@ -685,18 +695,25 @@ struct address_space_operations ext2_aops = {
        .bmap                   = ext2_bmap,
        .direct_IO              = ext2_direct_IO,
        .writepages             = ext2_writepages,
+       .migratepage            = buffer_migrate_page,
+};
+
+struct address_space_operations ext2_aops_xip = {
+       .bmap                   = ext2_bmap,
+       .get_xip_page           = ext2_get_xip_page,
 };
 
 struct address_space_operations ext2_nobh_aops = {
        .readpage               = ext2_readpage,
        .readpages              = ext2_readpages,
-       .writepage              = ext2_writepage,
+       .writepage              = ext2_nobh_writepage,
        .sync_page              = block_sync_page,
        .prepare_write          = ext2_nobh_prepare_write,
        .commit_write           = nobh_commit_write,
        .bmap                   = ext2_bmap,
        .direct_IO              = ext2_direct_IO,
        .writepages             = ext2_writepages,
+       .migratepage            = buffer_migrate_page,
 };
 
 /*
@@ -704,7 +721,7 @@ struct address_space_operations ext2_nobh_aops = {
  * or memcmp with zero_page, whatever is better for particular architecture.
  * Linus?
  */
-static inline int all_zeroes(u32 *p, u32 *q)
+static inline int all_zeroes(__le32 *p, __le32 *q)
 {
        while (p < q)
                if (*p++)
@@ -750,7 +767,7 @@ static Indirect *ext2_find_shared(struct inode *inode,
                                int depth,
                                int offsets[4],
                                Indirect chain[4],
-                               u32 *top)
+                               __le32 *top)
 {
        Indirect *partial, *p;
        int k, err;
@@ -770,7 +787,7 @@ static Indirect *ext2_find_shared(struct inode *inode,
                write_unlock(&EXT2_I(inode)->i_meta_lock);
                goto no_top;
        }
-       for (p=partial; p>chain && all_zeroes((u32*)p->bh->b_data,p->p); p--)
+       for (p=partial; p>chain && all_zeroes((__le32*)p->bh->b_data,p->p); p--)
                ;
        /*
         * OK, we've found the last block that must survive. The rest of our
@@ -805,7 +822,7 @@ no_top:
  *     stored as little-endian 32-bit) and updating @inode->i_blocks
  *     appropriately.
  */
-static inline void ext2_free_data(struct inode *inode, u32 *p, u32 *q)
+static inline void ext2_free_data(struct inode *inode, __le32 *p, __le32 *q)
 {
        unsigned long block_to_free = 0, count = 0;
        unsigned long nr;
@@ -845,7 +862,7 @@ static inline void ext2_free_data(struct inode *inode, u32 *p, u32 *q)
  *     stored as little-endian 32-bit) and updating @inode->i_blocks
  *     appropriately.
  */
-static void ext2_free_branches(struct inode *inode, u32 *p, u32 *q, int depth)
+static void ext2_free_branches(struct inode *inode, __le32 *p, __le32 *q, int depth)
 {
        struct buffer_head * bh;
        unsigned long nr;
@@ -869,8 +886,8 @@ static void ext2_free_branches(struct inode *inode, u32 *p, u32 *q, int depth)
                                continue;
                        }
                        ext2_free_branches(inode,
-                                          (u32*)bh->b_data,
-                                          (u32*)bh->b_data + addr_per_block,
+                                          (__le32*)bh->b_data,
+                                          (__le32*)bh->b_data + addr_per_block,
                                           depth);
                        bforget(bh);
                        ext2_free_blocks(inode, nr, 1);
@@ -880,14 +897,14 @@ static void ext2_free_branches(struct inode *inode, u32 *p, u32 *q, int depth)
                ext2_free_data(inode, p, q);
 }
 
-static void ext2_truncate_nocheck(struct inode * inode)
+void ext2_truncate (struct inode * inode)
 {
-       u32 *i_data = EXT2_I(inode)->i_data;
+       __le32 *i_data = EXT2_I(inode)->i_data;
        int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
        int offsets[4];
        Indirect chain[4];
        Indirect *partial;
-       int nr = 0;
+       __le32 nr = 0;
        int n;
        long iblock;
        unsigned blocksize;
@@ -897,6 +914,8 @@ static void ext2_truncate_nocheck(struct inode * inode)
                return;
        if (ext2_inode_is_fast_symlink(inode))
                return;
+       if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+               return;
 
        ext2_discard_prealloc(inode);
 
@@ -904,7 +923,9 @@ static void ext2_truncate_nocheck(struct inode * inode)
        iblock = (inode->i_size + blocksize-1)
                                        >> EXT2_BLOCK_SIZE_BITS(inode->i_sb);
 
-       if (test_opt(inode->i_sb, NOBH))
+       if (mapping_is_xip(inode->i_mapping))
+               xip_truncate_page(inode->i_mapping, inode->i_size);
+       else if (test_opt(inode->i_sb, NOBH))
                nobh_truncate_page(inode->i_mapping, inode->i_size);
        else
                block_truncate_page(inode->i_mapping,
@@ -933,7 +954,7 @@ static void ext2_truncate_nocheck(struct inode * inode)
        while (partial > chain) {
                ext2_free_branches(inode,
                                   partial->p + 1,
-                                  (u32*)partial->bh->b_data + addr_per_block,
+                                  (__le32*)partial->bh->b_data+addr_per_block,
                                   (chain+n-1) - partial);
                mark_buffer_dirty_inode(partial->bh, inode);
                brelse (partial->bh);
@@ -966,7 +987,7 @@ do_indirects:
                case EXT2_TIND_BLOCK:
                        ;
        }
-       inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+       inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
        if (inode_needs_sync(inode)) {
                sync_mapping_buffers(inode->i_mapping);
                ext2_sync_inode (inode);
@@ -1018,34 +1039,66 @@ Egdp:
        return ERR_PTR(-EIO);
 }
 
-void ext2_truncate (struct inode * inode)
-{
-       if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
-               return;
-       ext2_truncate_nocheck(inode);
-}
-
 void ext2_set_inode_flags(struct inode *inode)
 {
        unsigned int flags = EXT2_I(inode)->i_flags;
 
-       inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC);
-       if (flags & EXT2_SYNC_FL)
-               inode->i_flags |= S_SYNC;
-       if (flags & EXT2_APPEND_FL)
-               inode->i_flags |= S_APPEND;
+       inode->i_flags &= ~(S_IMMUTABLE | S_IUNLINK | S_BARRIER |
+               S_SYNC | S_APPEND | S_NOATIME | S_DIRSYNC);
+
        if (flags & EXT2_IMMUTABLE_FL)
                inode->i_flags |= S_IMMUTABLE;
        if (flags & EXT2_IUNLINK_FL)
                inode->i_flags |= S_IUNLINK;
        if (flags & EXT2_BARRIER_FL)
                inode->i_flags |= S_BARRIER;
+
+       if (flags & EXT2_SYNC_FL)
+               inode->i_flags |= S_SYNC;
+       if (flags & EXT2_APPEND_FL)
+               inode->i_flags |= S_APPEND;
        if (flags & EXT2_NOATIME_FL)
                inode->i_flags |= S_NOATIME;
        if (flags & EXT2_DIRSYNC_FL)
                inode->i_flags |= S_DIRSYNC;
 }
 
+int ext2_sync_flags(struct inode *inode)
+{
+       unsigned int oldflags, newflags;
+
+       oldflags = EXT2_I(inode)->i_flags;
+       newflags = oldflags & ~(EXT2_APPEND_FL |
+               EXT2_IMMUTABLE_FL | EXT2_IUNLINK_FL |
+               EXT2_BARRIER_FL | EXT2_NOATIME_FL |
+               EXT2_SYNC_FL | EXT2_DIRSYNC_FL);
+
+       if (IS_APPEND(inode))
+               newflags |= EXT2_APPEND_FL;
+       if (IS_IMMUTABLE(inode))
+               newflags |= EXT2_IMMUTABLE_FL;
+       if (IS_IUNLINK(inode))
+               newflags |= EXT2_IUNLINK_FL;
+       if (IS_BARRIER(inode))
+               newflags |= EXT2_BARRIER_FL;
+
+       /* we do not want to copy superblock flags */
+       if (inode->i_flags & S_NOATIME)
+               newflags |= EXT2_NOATIME_FL;
+       if (inode->i_flags & S_SYNC)
+               newflags |= EXT2_SYNC_FL;
+       if (inode->i_flags & S_DIRSYNC)
+               newflags |= EXT2_DIRSYNC_FL;
+
+       if (oldflags ^ newflags) {
+               EXT2_I(inode)->i_flags = newflags;
+               inode->i_ctime = CURRENT_TIME;
+               mark_inode_dirty(inode);
+       }
+
+       return 0;
+}
+
 void ext2_read_inode (struct inode * inode)
 {
        struct ext2_inode_info *ei = EXT2_I(inode);
@@ -1070,10 +1123,10 @@ void ext2_read_inode (struct inode * inode)
                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_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);
@@ -1122,11 +1175,16 @@ void ext2_read_inode (struct inode * inode)
 
        if (S_ISREG(inode->i_mode)) {
                inode->i_op = &ext2_file_inode_operations;
-               inode->i_fop = &ext2_file_operations;
-               if (test_opt(inode->i_sb, NOBH))
+               if (ext2_use_xip(inode->i_sb)) {
+                       inode->i_mapping->a_ops = &ext2_aops_xip;
+                       inode->i_fop = &ext2_xip_file_operations;
+               } else if (test_opt(inode->i_sb, NOBH)) {
                        inode->i_mapping->a_ops = &ext2_nobh_aops;
-               else
+                       inode->i_fop = &ext2_file_operations;
+               } else {
                        inode->i_mapping->a_ops = &ext2_aops;
+                       inode->i_fop = &ext2_file_operations;
+               }
        } else if (S_ISDIR(inode->i_mode)) {
                inode->i_op = &ext2_dir_inode_operations;
                inode->i_fop = &ext2_dir_operations;
@@ -1167,8 +1225,8 @@ static int ext2_update_inode(struct inode * inode, int do_sync)
        struct ext2_inode_info *ei = EXT2_I(inode);
        struct super_block *sb = inode->i_sb;
        ino_t ino = inode->i_ino;
-       uid_t uid = XIDINO_UID(inode->i_uid, inode->i_xid);
-       gid_t gid = XIDINO_GID(inode->i_gid, inode->i_xid);
+       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);
        struct buffer_head * bh;
        struct ext2_inode * raw_inode = ext2_get_inode(sb, ino, &bh);
        int n;
@@ -1203,7 +1261,7 @@ static int ext2_update_inode(struct inode * inode, int do_sync)
                raw_inode->i_uid_high = 0;
                raw_inode->i_gid_high = 0;
        }
-#ifdef CONFIG_INOXID_GID32
+#ifdef CONFIG_INOXID_INTERN
        raw_inode->i_raw_xid = cpu_to_le16(inode->i_xid);
 #endif
        raw_inode->i_links_count = cpu_to_le16(inode->i_nlink);
@@ -1269,9 +1327,9 @@ static int ext2_update_inode(struct inode * inode, int do_sync)
        return err;
 }
 
-void ext2_write_inode(struct inode *inode, int wait)
+int ext2_write_inode(struct inode *inode, int wait)
 {
-       ext2_update_inode(inode, wait);
+       return ext2_update_inode(inode, wait);
 }
 
 int ext2_sync_inode(struct inode *inode)
@@ -1283,27 +1341,6 @@ int ext2_sync_inode(struct inode *inode)
        return sync_inode(inode, &wbc);
 }
 
-int ext2_setattr_flags(struct inode *inode, unsigned int flags)
-{
-       unsigned int oldflags, newflags;
-
-       oldflags = EXT2_I(inode)->i_flags;
-       newflags = oldflags &
-               ~(EXT2_IMMUTABLE_FL | EXT2_IUNLINK_FL | EXT2_BARRIER_FL);       
-       if (flags & ATTR_FLAG_IMMUTABLE)
-               newflags |= EXT2_IMMUTABLE_FL;
-       if (flags & ATTR_FLAG_IUNLINK)
-               newflags |= EXT2_IUNLINK_FL;
-       if (flags & ATTR_FLAG_BARRIER)
-               newflags |= EXT2_BARRIER_FL;
-
-       if (oldflags ^ newflags) {
-               EXT2_I(inode)->i_flags = newflags;
-               inode->i_ctime = CURRENT_TIME;
-       }
-       return 0;
-}
-
 int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
 {
        struct inode *inode = dentry->d_inode;
@@ -1313,16 +1350,14 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
        if (error)
                return error;
        if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) ||
-           (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) {
+           (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid) ||
+           (iattr->ia_valid & ATTR_XID && iattr->ia_xid != inode->i_xid)) {
                error = DQUOT_TRANSFER(inode, iattr) ? -EDQUOT : 0;
                if (error)
                        return error;
        }
-       if (iattr->ia_valid & ATTR_ATTR_FLAG)
-               ext2_setattr_flags(inode, iattr->ia_attr_flags);
-
-       inode_setattr(inode, iattr);
-       if (iattr->ia_valid & ATTR_MODE)
+       error = inode_setattr(inode, iattr);
+       if (!error && (iattr->ia_valid & ATTR_MODE))
                error = ext2_acl_chmod(inode);
        return error;
 }