lkml.org 
[lkml]   [2000]   [Sep]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
SubjectRe: Large File support and blocks.
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/

\
 
 \ /
  Last update: 2005-03-22 12:38    [W:0.613 / U:0.316 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site