Re: Large File support and blocks.

From: Andi Kleen (ak@suse.de)
Date: Fri Sep 01 2000 - 07:44:04 EST


On Thu, Aug 31, 2000 at 09:50:35PM -0700, Richard Henderson wrote:
> On Fri, Sep 01, 2000 at 12:16:38AM +0300, Matti Aarnio wrote:
> > Also (I recall) because GCC's 'long long' related operations
> > and optimizations have been buggy in past, and there is no
> > sufficient experience to convince him that they work now better
> > with the recommended kernel compiling GCC version (egcs-1.1.2).
>
> To my knowlege it's only been speed related issues, not
> correctness issues, that have been the cause for the
> fear and loathing of long long.

There are several parts of XFS which do not compile correctly with gcc 2.95.2,
but do with egcs 1.1

For example consider the appended test case. It breaks with 2.95-stable
(from CVS March or so) because the bh->b_blocknr >>= block_bits;
shift is miscompiled. The problem seems to be that it forgets to reload
the %cl register used for the variable shift after the long long shift
before, leading to a bogus shift.

Another problem is that linus' do_div in asm-i386/div64.h seems to cause
miscompiled code when used in anything more complicated than printk (no
extracted test case yet sorry)

Assembly from gcc 2.95 for the
            bh->b_blocknr = (long)mp->pbm_bn +
                        (mp->pbm_offset >> inode->i_sb->s_blocksize_bits);
                bh->b_blocknr >>= block_bits;
                bh->b_state |= (1UL << 4 );
part of the program below:

        .L10:
        movl 48(%esp),%edx
        movl 4(%edx),%eax
        movl 4(%esi),%edx
        movb 8(%eax),%al
        movb %al,%cl <---------- sets %cl for the long long shift
        movl %edx,%eax
        movl %ecx,%edx
        shrdl %edx,%eax
        shrl %cl,%edx
        testb $32,%cl
        je .L19
        movl %edx,%eax
        xorl %edx,%edx
.L19:
        movl %eax,20(%esp)
        movl %edx,24(%esp)
        movl 20(%esp),%eax
        addl (%esi),%eax
        movl %ebp,%ecx
        shrl %cl,%eax <--------- uses %cl but it is not reloaded
        movl %eax,4(%ebx)

Test case:

struct page;

struct super_block {
        int dummy;
        unsigned long s_blocksize;
        unsigned char s_blocksize_bits;
};

struct inode {
        int dummy;
        struct super_block *i_sb;
};

struct buffer_head {
         
        struct buffer_head *b_next;
        unsigned long b_blocknr;
        unsigned long b_state;

        struct buffer_head *b_this_page;

        struct buffer_head **b_pprev;

};

 
typedef enum page_buf_bmap_flags_e {
        PBMF_EOF = 0x01,
        PBMF_HOLE = 0x02,
        PBMF_DELAY = 0x04,
        PBMF_FLUSH_OVERLAPS = 0x08,
        PBMF_READAHEAD = 0x10,
        PBMF_UNWRITTEN = 0x20,
                                         
        PBMF_DONTALLOC = 0x40,
        PBMF_NEW = 0x80
} page_buf_bmap_flags_t;

typedef int page_buf_daddr_t;

typedef unsigned long long loff_t;
typedef unsigned int size_t;

typedef struct page_buf_bmap_s {
        page_buf_daddr_t pbm_bn;
        loff_t pbm_offset;
        size_t pbm_bsize;
        page_buf_bmap_flags_t pbm_flags;
} page_buf_bmap_t;

typedef page_buf_bmap_t pb_bmap_t;

__pb_set_blocks_mp(
        struct inode *inode,
        struct page *page,
        page_buf_bmap_t *mp,
        int blocksize,
        int block_bits,
        int created_buffers,
        struct buffer_head *bh,
        struct buffer_head *head)
{
        block_bits -= inode->i_sb->s_blocksize_bits;

         

        for ( ; mp->pbm_bsize ; mp->pbm_bsize -= blocksize) {

                if (mp->pbm_flags & (PBMF_HOLE|PBMF_UNWRITTEN))
                        goto next_buffer;

                if ((mp->pbm_bn << inode->i_sb->s_blocksize_bits) % blocksize)
                {
                        return -1;
                }

                if (mp->pbm_offset % blocksize)
                        do { printk("kernel BUG at %s:%d!\n", "page_buf.c", 3801); __asm__ __volatile__(".byte 0x0f,0x0b"); } while (0) ;

                bh->b_blocknr = (long)mp->pbm_bn +
                        (mp->pbm_offset >> inode->i_sb->s_blocksize_bits);
                bh->b_blocknr >>= block_bits;
                bh->b_state |= (1UL << 4 );

                if (created_buffers && (mp->pbm_flags & PBMF_NEW))
                        bh->b_state |= (1UL << 5 );

                mp->pbm_bn += 1 << block_bits;
next_buffer:
                bh = bh->b_this_page;
                if (bh == head)
                        return 1;
        }
        return 0;
}

 

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Thu Sep 07 2000 - 21:00:11 EST