]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] m68k: AFFS update [1/20]
authorRoman Zippel <zippel@linux-m68k.org>
Tue, 7 May 2002 03:09:06 +0000 (20:09 -0700)
committerLinus Torvalds <torvalds@home.transmeta.com>
Tue, 7 May 2002 03:09:06 +0000 (20:09 -0700)
- sizeof changes from Kernel Janitor Project
- several bug fixes found with fsx

fs/affs/Changes
fs/affs/bitmap.c
fs/affs/file.c
fs/affs/super.c

index 421437eff8d3d34554163afd25697b230f15e79c..ee63080031678c205a2043febe118cccdd46a9fe 100644 (file)
@@ -28,6 +28,12 @@ Known bugs:
 
 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
 ------------
 
index c0e48f698ee740d07ea2a15303d47e29bb8514ff..2ff2854b0d7494bd374ab4272217bacc59e8385f 100644 (file)
@@ -296,7 +296,7 @@ affs_init_bitmap(struct super_block *sb)
        sbi->s_bmap_bits = sb->s_blocksize * 8 - 32;
        sbi->s_bmap_count = (sbi->s_partition_size - sbi->s_reserved +
                                 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);
        if (!sbi->s_bitmap) {
                printk(KERN_ERR "AFFS: Bitmap allocation failed\n");
index f59a2f9fd3de7613cb5ac13d04c5559cc2755ac1..86a98ea9d4bfff68105a253a674b7c7d3d41dafe 100644 (file)
@@ -507,7 +507,7 @@ affs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
 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;
@@ -515,6 +515,8 @@ affs_do_readpage_ofs(struct file *file, struct page *page, unsigned from, unsign
        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;
@@ -525,7 +527,9 @@ affs_do_readpage_ofs(struct file *file, struct page *page, unsigned from, unsign
                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++;
@@ -536,9 +540,8 @@ affs_do_readpage_ofs(struct file *file, struct page *page, unsigned from, unsign
 }
 
 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;
@@ -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);
        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) {
@@ -556,6 +559,8 @@ affs_extent_file_ofs(struct file *file, u32 newsize)
                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);
@@ -574,18 +579,21 @@ affs_extent_file_ofs(struct file *file, u32 newsize)
                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);
                }
@@ -593,18 +601,18 @@ affs_extent_file_ofs(struct file *file, u32 newsize)
                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;
 
@@ -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)
 {
-       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);
@@ -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);
                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);
@@ -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)
 {
-       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;
@@ -683,6 +691,8 @@ static int affs_commit_write_ofs(struct file *file, struct page *page, unsigned
                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);
@@ -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)->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);
                        }
                }
@@ -729,6 +740,8 @@ static int affs_commit_write_ofs(struct file *file, struct page *page, unsigned
                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);
@@ -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)->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)
@@ -805,9 +819,9 @@ affs_truncate(struct inode *inode)
        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) {
@@ -822,10 +836,8 @@ affs_truncate(struct inode *inode)
                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)
@@ -833,19 +845,25 @@ affs_truncate(struct inode *inode)
                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)
@@ -876,6 +894,19 @@ affs_truncate(struct inode *inode)
        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;
@@ -894,5 +925,5 @@ affs_truncate(struct inode *inode)
                ext_key = be32_to_cpu(AFFS_TAIL(sb, ext_bh)->extension);
                affs_brelse(ext_bh);
        }
-       unlock_kernel();
+       affs_free_prealloc(inode);
 }
index f7f9c4804ba921048be484ab7caf1d58b23a1471..01041d6930284cf32bad2c889dcc704ed68b89c1 100644 (file)
@@ -111,7 +111,7 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
                inode_init_once(&ei->vfs_inode);
        }
 }
+
 static int init_inodecache(void)
 {
        affs_inode_cachep = kmem_cache_create("affs_inode_cache",
@@ -299,7 +299,7 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
        if (!sbi)
                return -ENOMEM;
        sb->u.generic_sbp = sbi;
-       memset(sbi, 0, sizeof(struct affs_sb_info));
+       memset(sbi, 0, sizeof(*AFFS_SB));
        init_MUTEX(&sbi->s_bmlock);
 
        if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block,