#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");
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();
inode->i_size = 0;
if (inode->i_blocks)
- ext2_truncate_nocheck(inode);
+ ext2_truncate (inode);
ext2_free_inode (inode);
return;
}
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;
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;
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;
{
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++;
}
* 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);
/* 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)
* 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];
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;
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
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
.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,
};
/*
* 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++)
int depth,
int offsets[4],
Indirect chain[4],
- u32 *top)
+ __le32 *top)
{
Indirect *partial, *p;
int k, err;
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
* 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;
* 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;
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);
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;
return;
if (ext2_inode_is_fast_symlink(inode))
return;
+ if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+ return;
ext2_discard_prealloc(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,
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);
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);
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);
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);
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;
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;
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);
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)
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;
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;