X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fext2%2Finode.c;h=c6a012874ae80714d6b05509e1be339a51692b7b;hb=34a75f0025b9cf803b6a88db032e6ad6950c9313;hp=3a6b0883d5aa5bf0992c663527d2fbceb0252fad;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 3a6b0883d..c6a012874 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -34,6 +34,7 @@ #include #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]; @@ -597,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; @@ -642,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 @@ -667,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 @@ -686,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, }; /* @@ -705,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++) @@ -751,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; @@ -771,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 @@ -806,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; @@ -846,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; @@ -870,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); @@ -881,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; @@ -898,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); @@ -905,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, @@ -934,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); @@ -967,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); @@ -1019,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); @@ -1071,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); @@ -1123,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; @@ -1168,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; @@ -1204,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); @@ -1270,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) @@ -1284,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; @@ -1320,11 +1356,8 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr) 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; }