static int
affs_do_readpage_ofs(struct file *file, struct page *page, unsigned from, unsigned to)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = page->mapping->host;
struct super_block *sb = inode->i_sb;
struct buffer_head *bh;
char *data;
u32 tmp;
pr_debug("AFFS: read_page(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to);
+ if (from > to || to > PAGE_CACHE_SIZE)
+ BUG();
data = page_address(page);
bsize = AFFS_SB(sb)->s_data_blksize;
tmp = (page->index << PAGE_CACHE_SHIFT) + from;
bh = affs_bread_ino(inode, bidx, 0);
if (IS_ERR(bh))
return PTR_ERR(bh);
- tmp = min(bsize - boff, from - to);
+ tmp = min(bsize - boff, to - from);
+ if (from + tmp > to || tmp > bsize)
+ BUG();
memcpy(data + from, AFFS_DATA(bh) + boff, tmp);
affs_brelse(bh);
bidx++;
}
static int
-affs_extent_file_ofs(struct file *file, u32 newsize)
+affs_extent_file_ofs(struct inode *inode, u32 newsize)
{
- struct inode *inode = file->f_dentry->d_inode;
struct super_block *sb = inode->i_sb;
struct buffer_head *bh, *prev_bh;
u32 bidx, boff;
pr_debug("AFFS: extent_file(%u, %d)\n", (u32)inode->i_ino, newsize);
bsize = AFFS_SB(sb)->s_data_blksize;
bh = NULL;
- size = inode->i_size;
+ size = AFFS_I(inode)->mmu_private;
bidx = size / bsize;
boff = size % bsize;
if (boff) {
if (IS_ERR(bh))
return PTR_ERR(bh);
tmp = min(bsize - boff, newsize - size);
+ if (boff + tmp > bsize || tmp > bsize)
+ BUG();
memset(AFFS_DATA(bh) + boff, 0, tmp);
AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp);
affs_fix_checksum(sb, bh);
if (IS_ERR(bh))
goto out;
tmp = min(bsize, newsize - size);
+ if (tmp > bsize)
+ BUG();
AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);
AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);
affs_fix_checksum(sb, bh);
+ bh->b_state &= ~(1UL << BH_New);
mark_buffer_dirty_inode(bh, inode);
if (prev_bh) {
u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
if (tmp)
- affs_warning(sb, "prepare_write_ofs", "next block already set for %d (%d)", bidx, tmp);
+ affs_warning(sb, "extent_file_ofs", "next block already set for %d (%d)", bidx, tmp);
AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
- affs_adjust_checksum(prev_bh, bidx - tmp);
+ affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp);
mark_buffer_dirty_inode(prev_bh, inode);
affs_brelse(prev_bh);
}
bidx++;
}
affs_brelse(bh);
- inode->i_size = AFFS_I(inode)->mmu_private = size;
+ inode->i_size = AFFS_I(inode)->mmu_private = newsize;
return 0;
out:
- inode->i_size = AFFS_I(inode)->mmu_private = size;
+ inode->i_size = AFFS_I(inode)->mmu_private = newsize;
return PTR_ERR(bh);
}
static int
affs_readpage_ofs(struct file *file, struct page *page)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = page->mapping->host;
u32 to;
int err;
static int affs_prepare_write_ofs(struct file *file, struct page *page, unsigned from, unsigned to)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = page->mapping->host;
u32 size, offset;
u32 tmp;
int err = 0;
pr_debug("AFFS: prepare_write(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to);
- if (PageUptodate(page))
- return 0;
-
- size = inode->i_size;
offset = page->index << PAGE_CACHE_SHIFT;
- if (offset + from > size) {
- err = affs_extent_file_ofs(file, offset + from);
+ if (offset + from > AFFS_I(inode)->mmu_private) {
+ err = affs_extent_file_ofs(inode, offset + from);
if (err)
return err;
}
+ size = inode->i_size;
+
+ if (PageUptodate(page))
+ return 0;
if (from) {
err = affs_do_readpage_ofs(file, page, 0, from);
memset(page_address(page) + to, 0, PAGE_CACHE_SIZE - to);
if (size > offset + to) {
if (size < offset + PAGE_CACHE_SIZE)
- tmp = size & PAGE_CACHE_MASK;
+ tmp = size & ~PAGE_CACHE_MASK;
else
tmp = PAGE_CACHE_SIZE;
err = affs_do_readpage_ofs(file, page, to, tmp);
static int affs_commit_write_ofs(struct file *file, struct page *page, unsigned from, unsigned to)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = page->mapping->host;
struct super_block *sb = inode->i_sb;
struct buffer_head *bh, *prev_bh;
char *data;
if (IS_ERR(bh))
return PTR_ERR(bh);
tmp = min(bsize - boff, to - from);
+ if (boff + tmp > bsize || tmp > bsize)
+ BUG();
memcpy(AFFS_DATA(bh) + boff, data + from, tmp);
AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp);
affs_fix_checksum(sb, bh);
AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
AFFS_DATA_HEAD(bh)->size = cpu_to_be32(bsize);
AFFS_DATA_HEAD(bh)->next = 0;
+ bh->b_state &= ~(1UL << BH_New);
if (prev_bh) {
u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
if (tmp)
- affs_warning(sb, "prepare_write_ofs", "next block already set for %d (%d)", bidx, tmp);
+ affs_warning(sb, "commit_write_ofs", "next block already set for %d (%d)", bidx, tmp);
AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
- affs_adjust_checksum(prev_bh, bidx - tmp);
+ affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp);
mark_buffer_dirty_inode(prev_bh, inode);
}
}
if (IS_ERR(bh))
goto out;
tmp = min(bsize, to - from);
+ if (tmp > bsize)
+ BUG();
memcpy(AFFS_DATA(bh), data + from, tmp);
if (buffer_new(bh)) {
AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);
AFFS_DATA_HEAD(bh)->next = 0;
+ bh->b_state &= ~(1UL << BH_New);
if (prev_bh) {
u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
if (tmp)
- affs_warning(sb, "prepare_write_ofs", "next block already set for %d (%d)", bidx, tmp);
+ affs_warning(sb, "commit_write_ofs", "next block already set for %d (%d)", bidx, tmp);
AFFS_DATA_HEAD(prev_bh)->next = cpu_to_be32(bh->b_blocknr);
- affs_adjust_checksum(prev_bh, bidx - tmp);
+ affs_adjust_checksum(prev_bh, bh->b_blocknr - tmp);
mark_buffer_dirty_inode(prev_bh, inode);
}
} else if (be32_to_cpu(AFFS_DATA_HEAD(bh)->size) < tmp)
struct buffer_head *ext_bh;
int i;
- pr_debug("AFFS: truncate(inode=%d, size=%u)\n", (u32)inode->i_ino, (u32)inode->i_size);
+ pr_debug("AFFS: truncate(inode=%d, oldsize=%u, newsize=%u)\n",
+ (u32)inode->i_ino, (u32)AFFS_I(inode)->mmu_private, (u32)inode->i_size);
- lock_kernel();
last_blk = 0;
ext = 0;
if (inode->i_size) {
int res;
page = grab_cache_page(mapping, size >> PAGE_CACHE_SHIFT);
- if (!page) {
- unlock_kernel();
+ if (!page)
return;
- }
size = (size & (PAGE_CACHE_SIZE - 1)) + 1;
res = mapping->a_ops->prepare_write(NULL, page, size, size);
if (!res)
unlock_page(page);
page_cache_release(page);
mark_inode_dirty(inode);
- unlock_kernel();
return;
- } else if (inode->i_size == AFFS_I(inode)->mmu_private) {
- unlock_kernel();
+ } else if (inode->i_size == AFFS_I(inode)->mmu_private)
return;
- }
// lock cache
ext_bh = affs_get_extblock(inode, ext);
+ if (IS_ERR(ext_bh)) {
+ affs_warning(sb, "truncate", "unexpected read error for ext block %u (%d)",
+ ext, PTR_ERR(ext_bh));
+ return;
+ }
if (AFFS_I(inode)->i_lc) {
/* clear linear cache */
- for (i = (ext + 1) >> AFFS_I(inode)->i_lc_shift; i < AFFS_LC_SIZE; i++)
- AFFS_I(inode)->i_lc[i] = 0;
+ i = (ext + 1) >> AFFS_I(inode)->i_lc_shift;
+ if (AFFS_I(inode)->i_lc_size > i) {
+ AFFS_I(inode)->i_lc_size = i;
+ for (; i < AFFS_LC_SIZE; i++)
+ AFFS_I(inode)->i_lc[i] = 0;
+ }
/* clear associative cache */
for (i = 0; i < AFFS_AC_SIZE; i++)
if (AFFS_I(inode)->i_ac[i].ext >= ext)
if (inode->i_size) {
AFFS_I(inode)->i_blkcnt = last_blk + 1;
AFFS_I(inode)->i_extcnt = ext + 1;
+ if (AFFS_SB(sb)->s_flags & SF_OFS) {
+ struct buffer_head *bh = affs_bread_ino(inode, last_blk, 0);
+ u32 tmp;
+ if (IS_ERR(ext_bh)) {
+ affs_warning(sb, "truncate", "unexpected read error for last block %u (%d)",
+ ext, PTR_ERR(ext_bh));
+ return;
+ }
+ tmp = be32_to_cpu(AFFS_DATA_HEAD(bh)->next);
+ AFFS_DATA_HEAD(bh)->next = 0;
+ affs_adjust_checksum(bh, -tmp);
+ affs_brelse(bh);
+ }
} else {
AFFS_I(inode)->i_blkcnt = 0;
AFFS_I(inode)->i_extcnt = 1;
ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension);
affs_brelse(ext_bh);
}
- unlock_kernel();
+ affs_free_prealloc(inode);
}