Commit 60ee061e authored by Roman Zippel's avatar Roman Zippel Committed by Linus Torvalds

[PATCH] m68k: AFFS update [1/20]

- sizeof changes from Kernel Janitor Project
- several bug fixes found with fsx
parent 3981b9e7
...@@ -28,6 +28,12 @@ Known bugs: ...@@ -28,6 +28,12 @@ Known bugs:
Please direct bug reports to: zippel@linux-m68k.org Please direct bug reports to: zippel@linux-m68k.org
Version 3.19
------------
- sizeof changes from Kernel Janitor Project
- several bug fixes found with fsx
Version 3.18 Version 3.18
------------ ------------
......
...@@ -296,7 +296,7 @@ affs_init_bitmap(struct super_block *sb) ...@@ -296,7 +296,7 @@ affs_init_bitmap(struct super_block *sb)
sbi->s_bmap_bits = sb->s_blocksize * 8 - 32; sbi->s_bmap_bits = sb->s_blocksize * 8 - 32;
sbi->s_bmap_count = (sbi->s_partition_size - sbi->s_reserved + sbi->s_bmap_count = (sbi->s_partition_size - sbi->s_reserved +
sbi->s_bmap_bits - 1) / sbi->s_bmap_bits; sbi->s_bmap_bits - 1) / sbi->s_bmap_bits;
size = sbi->s_bmap_count * sizeof(struct affs_bm_info); size = sbi->s_bmap_count * sizeof(*bm);
bm = sbi->s_bitmap = kmalloc(size, GFP_KERNEL); bm = sbi->s_bitmap = kmalloc(size, GFP_KERNEL);
if (!sbi->s_bitmap) { if (!sbi->s_bitmap) {
printk(KERN_ERR "AFFS: Bitmap allocation failed\n"); printk(KERN_ERR "AFFS: Bitmap allocation failed\n");
......
...@@ -507,7 +507,7 @@ affs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos) ...@@ -507,7 +507,7 @@ affs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
static int static int
affs_do_readpage_ofs(struct file *file, struct page *page, unsigned from, unsigned to) 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 super_block *sb = inode->i_sb;
struct buffer_head *bh; struct buffer_head *bh;
char *data; char *data;
...@@ -515,6 +515,8 @@ affs_do_readpage_ofs(struct file *file, struct page *page, unsigned from, unsign ...@@ -515,6 +515,8 @@ affs_do_readpage_ofs(struct file *file, struct page *page, unsigned from, unsign
u32 tmp; u32 tmp;
pr_debug("AFFS: read_page(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to); 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); data = page_address(page);
bsize = AFFS_SB(sb)->s_data_blksize; bsize = AFFS_SB(sb)->s_data_blksize;
tmp = (page->index << PAGE_CACHE_SHIFT) + from; tmp = (page->index << PAGE_CACHE_SHIFT) + from;
...@@ -525,7 +527,9 @@ affs_do_readpage_ofs(struct file *file, struct page *page, unsigned from, unsign ...@@ -525,7 +527,9 @@ affs_do_readpage_ofs(struct file *file, struct page *page, unsigned from, unsign
bh = affs_bread_ino(inode, bidx, 0); bh = affs_bread_ino(inode, bidx, 0);
if (IS_ERR(bh)) if (IS_ERR(bh))
return PTR_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); memcpy(data + from, AFFS_DATA(bh) + boff, tmp);
affs_brelse(bh); affs_brelse(bh);
bidx++; bidx++;
...@@ -536,9 +540,8 @@ affs_do_readpage_ofs(struct file *file, struct page *page, unsigned from, unsign ...@@ -536,9 +540,8 @@ affs_do_readpage_ofs(struct file *file, struct page *page, unsigned from, unsign
} }
static int 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 super_block *sb = inode->i_sb;
struct buffer_head *bh, *prev_bh; struct buffer_head *bh, *prev_bh;
u32 bidx, boff; u32 bidx, boff;
...@@ -548,7 +551,7 @@ affs_extent_file_ofs(struct file *file, u32 newsize) ...@@ -548,7 +551,7 @@ affs_extent_file_ofs(struct file *file, u32 newsize)
pr_debug("AFFS: extent_file(%u, %d)\n", (u32)inode->i_ino, newsize); pr_debug("AFFS: extent_file(%u, %d)\n", (u32)inode->i_ino, newsize);
bsize = AFFS_SB(sb)->s_data_blksize; bsize = AFFS_SB(sb)->s_data_blksize;
bh = NULL; bh = NULL;
size = inode->i_size; size = AFFS_I(inode)->mmu_private;
bidx = size / bsize; bidx = size / bsize;
boff = size % bsize; boff = size % bsize;
if (boff) { if (boff) {
...@@ -556,6 +559,8 @@ affs_extent_file_ofs(struct file *file, u32 newsize) ...@@ -556,6 +559,8 @@ affs_extent_file_ofs(struct file *file, u32 newsize)
if (IS_ERR(bh)) if (IS_ERR(bh))
return PTR_ERR(bh); return PTR_ERR(bh);
tmp = min(bsize - boff, newsize - size); tmp = min(bsize - boff, newsize - size);
if (boff + tmp > bsize || tmp > bsize)
BUG();
memset(AFFS_DATA(bh) + boff, 0, tmp); 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_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp);
affs_fix_checksum(sb, bh); affs_fix_checksum(sb, bh);
...@@ -574,18 +579,21 @@ affs_extent_file_ofs(struct file *file, u32 newsize) ...@@ -574,18 +579,21 @@ affs_extent_file_ofs(struct file *file, u32 newsize)
if (IS_ERR(bh)) if (IS_ERR(bh))
goto out; goto out;
tmp = min(bsize, newsize - size); tmp = min(bsize, newsize - size);
if (tmp > bsize)
BUG();
AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA); 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)->key = cpu_to_be32(inode->i_ino);
AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx); AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp); AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);
affs_fix_checksum(sb, bh); affs_fix_checksum(sb, bh);
bh->b_state &= ~(1UL << BH_New);
mark_buffer_dirty_inode(bh, inode); mark_buffer_dirty_inode(bh, inode);
if (prev_bh) { if (prev_bh) {
u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next); u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
if (tmp) 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_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); mark_buffer_dirty_inode(prev_bh, inode);
affs_brelse(prev_bh); affs_brelse(prev_bh);
} }
...@@ -593,18 +601,18 @@ affs_extent_file_ofs(struct file *file, u32 newsize) ...@@ -593,18 +601,18 @@ affs_extent_file_ofs(struct file *file, u32 newsize)
bidx++; bidx++;
} }
affs_brelse(bh); affs_brelse(bh);
inode->i_size = AFFS_I(inode)->mmu_private = size; inode->i_size = AFFS_I(inode)->mmu_private = newsize;
return 0; return 0;
out: out:
inode->i_size = AFFS_I(inode)->mmu_private = size; inode->i_size = AFFS_I(inode)->mmu_private = newsize;
return PTR_ERR(bh); return PTR_ERR(bh);
} }
static int static int
affs_readpage_ofs(struct file *file, struct page *page) 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; u32 to;
int err; int err;
...@@ -624,22 +632,22 @@ affs_readpage_ofs(struct file *file, struct page *page) ...@@ -624,22 +632,22 @@ affs_readpage_ofs(struct file *file, struct page *page)
static int affs_prepare_write_ofs(struct file *file, struct page *page, unsigned from, unsigned to) 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 size, offset;
u32 tmp; u32 tmp;
int err = 0; int err = 0;
pr_debug("AFFS: prepare_write(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to); 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; offset = page->index << PAGE_CACHE_SHIFT;
if (offset + from > size) { if (offset + from > AFFS_I(inode)->mmu_private) {
err = affs_extent_file_ofs(file, offset + from); err = affs_extent_file_ofs(inode, offset + from);
if (err) if (err)
return err; return err;
} }
size = inode->i_size;
if (PageUptodate(page))
return 0;
if (from) { if (from) {
err = affs_do_readpage_ofs(file, page, 0, from); err = affs_do_readpage_ofs(file, page, 0, from);
...@@ -650,7 +658,7 @@ static int affs_prepare_write_ofs(struct file *file, struct page *page, unsigned ...@@ -650,7 +658,7 @@ static int affs_prepare_write_ofs(struct file *file, struct page *page, unsigned
memset(page_address(page) + to, 0, PAGE_CACHE_SIZE - to); memset(page_address(page) + to, 0, PAGE_CACHE_SIZE - to);
if (size > offset + to) { if (size > offset + to) {
if (size < offset + PAGE_CACHE_SIZE) if (size < offset + PAGE_CACHE_SIZE)
tmp = size & PAGE_CACHE_MASK; tmp = size & ~PAGE_CACHE_MASK;
else else
tmp = PAGE_CACHE_SIZE; tmp = PAGE_CACHE_SIZE;
err = affs_do_readpage_ofs(file, page, to, tmp); err = affs_do_readpage_ofs(file, page, to, tmp);
...@@ -661,7 +669,7 @@ static int affs_prepare_write_ofs(struct file *file, struct page *page, unsigned ...@@ -661,7 +669,7 @@ static int affs_prepare_write_ofs(struct file *file, struct page *page, unsigned
static int affs_commit_write_ofs(struct file *file, struct page *page, unsigned from, unsigned to) 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 super_block *sb = inode->i_sb;
struct buffer_head *bh, *prev_bh; struct buffer_head *bh, *prev_bh;
char *data; char *data;
...@@ -683,6 +691,8 @@ static int affs_commit_write_ofs(struct file *file, struct page *page, unsigned ...@@ -683,6 +691,8 @@ static int affs_commit_write_ofs(struct file *file, struct page *page, unsigned
if (IS_ERR(bh)) if (IS_ERR(bh))
return PTR_ERR(bh); return PTR_ERR(bh);
tmp = min(bsize - boff, to - from); tmp = min(bsize - boff, to - from);
if (boff + tmp > bsize || tmp > bsize)
BUG();
memcpy(AFFS_DATA(bh) + boff, data + from, tmp); 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_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp);
affs_fix_checksum(sb, bh); affs_fix_checksum(sb, bh);
...@@ -707,12 +717,13 @@ static int affs_commit_write_ofs(struct file *file, struct page *page, unsigned ...@@ -707,12 +717,13 @@ static int affs_commit_write_ofs(struct file *file, struct page *page, unsigned
AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx); AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
AFFS_DATA_HEAD(bh)->size = cpu_to_be32(bsize); AFFS_DATA_HEAD(bh)->size = cpu_to_be32(bsize);
AFFS_DATA_HEAD(bh)->next = 0; AFFS_DATA_HEAD(bh)->next = 0;
bh->b_state &= ~(1UL << BH_New);
if (prev_bh) { if (prev_bh) {
u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next); u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
if (tmp) 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_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); mark_buffer_dirty_inode(prev_bh, inode);
} }
} }
...@@ -729,6 +740,8 @@ static int affs_commit_write_ofs(struct file *file, struct page *page, unsigned ...@@ -729,6 +740,8 @@ static int affs_commit_write_ofs(struct file *file, struct page *page, unsigned
if (IS_ERR(bh)) if (IS_ERR(bh))
goto out; goto out;
tmp = min(bsize, to - from); tmp = min(bsize, to - from);
if (tmp > bsize)
BUG();
memcpy(AFFS_DATA(bh), data + from, tmp); memcpy(AFFS_DATA(bh), data + from, tmp);
if (buffer_new(bh)) { if (buffer_new(bh)) {
AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA); AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
...@@ -736,12 +749,13 @@ static int affs_commit_write_ofs(struct file *file, struct page *page, unsigned ...@@ -736,12 +749,13 @@ static int affs_commit_write_ofs(struct file *file, struct page *page, unsigned
AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx); AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp); AFFS_DATA_HEAD(bh)->size = cpu_to_be32(tmp);
AFFS_DATA_HEAD(bh)->next = 0; AFFS_DATA_HEAD(bh)->next = 0;
bh->b_state &= ~(1UL << BH_New);
if (prev_bh) { if (prev_bh) {
u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next); u32 tmp = be32_to_cpu(AFFS_DATA_HEAD(prev_bh)->next);
if (tmp) 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_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); mark_buffer_dirty_inode(prev_bh, inode);
} }
} else if (be32_to_cpu(AFFS_DATA_HEAD(bh)->size) < tmp) } else if (be32_to_cpu(AFFS_DATA_HEAD(bh)->size) < tmp)
...@@ -805,9 +819,9 @@ affs_truncate(struct inode *inode) ...@@ -805,9 +819,9 @@ affs_truncate(struct inode *inode)
struct buffer_head *ext_bh; struct buffer_head *ext_bh;
int i; 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; last_blk = 0;
ext = 0; ext = 0;
if (inode->i_size) { if (inode->i_size) {
...@@ -822,10 +836,8 @@ affs_truncate(struct inode *inode) ...@@ -822,10 +836,8 @@ affs_truncate(struct inode *inode)
int res; int res;
page = grab_cache_page(mapping, size >> PAGE_CACHE_SHIFT); page = grab_cache_page(mapping, size >> PAGE_CACHE_SHIFT);
if (!page) { if (!page)
unlock_kernel();
return; return;
}
size = (size & (PAGE_CACHE_SIZE - 1)) + 1; size = (size & (PAGE_CACHE_SIZE - 1)) + 1;
res = mapping->a_ops->prepare_write(NULL, page, size, size); res = mapping->a_ops->prepare_write(NULL, page, size, size);
if (!res) if (!res)
...@@ -833,19 +845,25 @@ affs_truncate(struct inode *inode) ...@@ -833,19 +845,25 @@ affs_truncate(struct inode *inode)
unlock_page(page); unlock_page(page);
page_cache_release(page); page_cache_release(page);
mark_inode_dirty(inode); mark_inode_dirty(inode);
unlock_kernel();
return; return;
} else if (inode->i_size == AFFS_I(inode)->mmu_private) { } else if (inode->i_size == AFFS_I(inode)->mmu_private)
unlock_kernel();
return; return;
}
// lock cache // lock cache
ext_bh = affs_get_extblock(inode, ext); 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) { if (AFFS_I(inode)->i_lc) {
/* clear linear cache */ /* clear linear cache */
for (i = (ext + 1) >> AFFS_I(inode)->i_lc_shift; i < AFFS_LC_SIZE; i++) 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; AFFS_I(inode)->i_lc[i] = 0;
}
/* clear associative cache */ /* clear associative cache */
for (i = 0; i < AFFS_AC_SIZE; i++) for (i = 0; i < AFFS_AC_SIZE; i++)
if (AFFS_I(inode)->i_ac[i].ext >= ext) if (AFFS_I(inode)->i_ac[i].ext >= ext)
...@@ -876,6 +894,19 @@ affs_truncate(struct inode *inode) ...@@ -876,6 +894,19 @@ affs_truncate(struct inode *inode)
if (inode->i_size) { if (inode->i_size) {
AFFS_I(inode)->i_blkcnt = last_blk + 1; AFFS_I(inode)->i_blkcnt = last_blk + 1;
AFFS_I(inode)->i_extcnt = ext + 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 { } else {
AFFS_I(inode)->i_blkcnt = 0; AFFS_I(inode)->i_blkcnt = 0;
AFFS_I(inode)->i_extcnt = 1; AFFS_I(inode)->i_extcnt = 1;
...@@ -894,5 +925,5 @@ affs_truncate(struct inode *inode) ...@@ -894,5 +925,5 @@ affs_truncate(struct inode *inode)
ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension); ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension);
affs_brelse(ext_bh); affs_brelse(ext_bh);
} }
unlock_kernel(); affs_free_prealloc(inode);
} }
...@@ -299,7 +299,7 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -299,7 +299,7 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
if (!sbi) if (!sbi)
return -ENOMEM; return -ENOMEM;
sb->u.generic_sbp = sbi; sb->u.generic_sbp = sbi;
memset(sbi, 0, sizeof(struct affs_sb_info)); memset(sbi, 0, sizeof(*AFFS_SB));
init_MUTEX(&sbi->s_bmlock); init_MUTEX(&sbi->s_bmlock);
if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block, if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment