Oops on 2.2.14 while doing direct I/O. Offending code is attached. If
I use a call to getblk() instead of local allocating the buffer heads,
it's doesn't crash. I have checked that 512 byte aligned memory **IS**
being passed to the drivers. Driver is IDE.
Jeff
#if (LINUX_20 | LINUX_22)
//
// low level disk sector interface routines
//
struct buffer_head *bh_head = 0;
struct buffer_head *bh_tail = 0;
ULONG bh_count = 0;
#if (LINUX_SLEEP)
struct semaphore bh_semaphore = MUTEX;
#endif
void lock_bh_free(void)
{
#if (LINUX_SLEEP)
if (WaitOnSemaphore(&bh_semaphore) == -EINTR)
NWFSPrint("lock bh was interrupted\n");
#endif
}
void unlock_bh_free(void)
{
#if (LINUX_SLEEP)
SignalSemaphore(&bh_semaphore);
#endif
}
void put_bh(struct buffer_head *bh)
{
lock_bh_free();
if (bh_count > MAX_BUFFER_HEADS)
{
unlock_bh_free();
NWFSFree(bh);
return;
}
if (!bh_head)
{
bh_head = bh_tail = bh;
bh->b_next_free = bh->b_prev_free = 0;
}
else
{
bh_tail->b_next_free = bh;
bh->b_next_free = 0;
bh->b_prev_free = bh_tail;
bh_tail = bh;
}
bh_count++;
unlock_bh_free();
return;
}
struct buffer_head *get_bh(void)
{
struct buffer_head *bh;
lock_bh_free();
if (bh_head)
{
bh = bh_head;
bh_head = bh->b_next_free;
if (bh_head)
bh_head->b_prev_free = NULL;
else
bh_tail = NULL;
if (bh_count)
bh_count--;
bh->b_next_free = bh->b_prev_free = 0;
unlock_bh_free();
return bh;
}
else
{
unlock_bh_free();
#if (LINUX_20 | LINUX_22)
bh = kmalloc(sizeof(struct buffer_head), GFP_BUFFER);
#else
bh = NWFSIOAlloc(sizeof(struct buffer_head), BH_TAG);
#endif
if (!bh)
return 0;
NWFSSet(bh, 0, sizeof(struct buffer_head));
return bh;
}
unlock_bh_free();
return 0;
}
void free_bh_list(void)
{
struct buffer_head *bh;
lock_bh_free();
while (bh_head)
{
bh = bh_head;
bh_head = bh->b_next_free;
if (bh_count)
bh_count--;
#if (LINUX_20 | LINUX_22)
kfree(bh);
#else
NWFSFree(bh);
#endif
}
bh_head = bh_tail = 0;
unlock_bh_free();
return;
}
#define LINUX_BUFFER_CACHE 1
#if (LINUX_BUFFER_CACHE)
ULONG pReadDiskSectors(ULONG disk, ULONG StartingLBA, BYTE *Sector,
ULONG sectors, ULONG readAhead)
{
register ULONG i, bytesRead = 0;
register ULONG bps;
register NWDISK *NWDisk;
register ULONG read_error = 0;
struct buffer_head *bh[sectors];
NWDisk = SystemDisk[disk];
bps = NWDisk->BytesPerSector;
for (i=0; i < sectors; i++)
{
if (!(bh[i] = getblk((ULONG)NWDisk->PhysicalDiskHandle,
(StartingLBA + i), bps)))
{
for (i=0; i < sectors; i++)
if (bh[i])
brelse(bh[i]);
return 0;
}
}
ll_rw_block(READA, sectors, bh);
for(i=0; i < sectors; i++)
{
wait_on_buffer(bh[i]);
if (buffer_uptodate(bh[i]))
{
NWFSCopy(&Sector[i * bps], bh[i]->b_data, bps);
bytesRead += bps;
}
else
read_error = 1;
brelse(bh[i]);
}
return (read_error ? 0 : bytesRead);
}
ULONG pWriteDiskSectors(ULONG disk, ULONG StartingLBA, BYTE *Sector,
ULONG sectors, ULONG readAhead)
{
register ULONG i, bytesWritten = 0;
register ULONG bps;
struct buffer_head *bh[sectors];
register ULONG write_error = 0;
register NWDISK *NWDisk;
NWDisk = SystemDisk[disk];
bps = NWDisk->BytesPerSector;
for (i=0; i < sectors; i++)
{
if (!(bh[i] = getblk((ULONG)NWDisk->PhysicalDiskHandle,
(StartingLBA + i), bps)))
{
for (i=0; i < sectors; i++)
if (bh[i])
brelse(bh[i]);
return 0;
}
NWFSCopy(bh[i]->b_data, &Sector[i * bps], bps);
mark_buffer_uptodate(bh[i], 1);
mark_buffer_dirty(bh[i], 0);
bytesWritten += bps;
}
ll_rw_block(WRITEA, sectors, bh);
for (i=0; i < sectors; i++)
{
wait_on_buffer(bh[i]);
if (!buffer_uptodate(bh[i]))
write_error = 1;
brelse(bh[i]);
}
run_task_queue(&tq_disk);
return (write_error ? 0 : bytesWritten);
}
ULONG pZeroFillDiskSectors(ULONG disk, ULONG StartingLBA, ULONG sectors,
ULONG readAhead)
{
register ULONG i, bytesWritten = 0;
register ULONG bps;
struct buffer_head *bh[sectors];
register ULONG write_error = 0;
register NWDISK *NWDisk;
NWDisk = SystemDisk[disk];
bps = NWDisk->BytesPerSector;
for (i=0; i < sectors; i++)
{
if (!(bh[i] = getblk((ULONG)NWDisk->PhysicalDiskHandle,
(StartingLBA + i), bps)))
{
for (i=0; i < sectors; i++)
if (bh[i])
brelse(bh[i]);
return 0;
}
NWFSSet(bh[i]->b_data, 0, bps);
mark_buffer_uptodate(bh[i], 1);
mark_buffer_dirty(bh[i], 0);
bytesWritten += bps;
}
ll_rw_block(WRITEA, sectors, bh);
for (i=0; i < sectors; i++)
{
wait_on_buffer(bh[i]);
if (!buffer_uptodate(bh[i]))
write_error = 1;
brelse(bh[i]);
}
return (write_error ? 0 : bytesWritten);
}
#else
//
// THIS CODE CRASHES WITH AN OOPS MESSAGE UNDER 2.2.14 (and all 2.2.X
kernels)
//
//
// this case assumes we will use the NWFS buffer cache and not allow
// cache sharing with the linux buffer cache.
//
ULONG pReadDiskSectors(ULONG disk, ULONG StartingLBA, BYTE *Sector,
ULONG sectors, ULONG readAhead)
{
register ULONG i, j, bytesRead = 0;
register ULONG bps;
register NWDISK *NWDisk;
register ULONG read_error = 0;
struct buffer_head *bh[sectors];
NWDisk = SystemDisk[disk];
bps = NWDisk->BytesPerSector;
for (i=0; i < sectors; i++)
{
bh[i] = get_bh();
if (!bh[i])
{
for (j=0; j < i; j++)
if (bh[j])
put_bh(bh[j]);
return 0;
}
}
for (i=0; i < sectors; i++)
{
bh[i]->b_this_page = bh[(i + 1) % sectors]; // create circular
list
bh[i]->b_state = 0;
bh[i]->b_next_free = NULL;
bh[i]->b_count = 0;
bh[i]->b_size = 512;
bh[i]->b_data = (char *)&Sector[i * bps];
bh[i]->b_list = BUF_CLEAN;
bh[i]->b_dev = (int)NWDisk->PhysicalDiskHandle;
bh[i]->b_blocknr = (StartingLBA + i);
bh[i]->b_count = 1;
bh[i]->b_flushtime = 0;
clear_bit(BH_Uptodate, &bh[i]->b_state);
}
ll_rw_block(READA, sectors, bh);
for(i=0; i < sectors; i++)
{
wait_on_buffer(bh[i]);
if (buffer_uptodate(bh[i]))
bytesRead += bps;
else
read_error = 1;
put_bh(bh[i]);
}
return (read_error ? 0 : bytesRead);
}
ULONG pWriteDiskSectors(ULONG disk, ULONG StartingLBA, BYTE *Sector,
ULONG sectors, ULONG readAhead)
{
register ULONG i, j, bytesWritten = 0;
register ULONG bps;
register ULONG write_error = 0;
register NWDISK *NWDisk;
struct buffer_head *bh[sectors];
NWDisk = SystemDisk[disk];
bps = NWDisk->BytesPerSector;
for (i=0; i < sectors; i++)
{
bh[i] = get_bh();
if (!bh[i])
{
for (j=0; j < i; j++)
if (bh[j])
put_bh(bh[j]);
return 0;
}
}
for (i=0; i < sectors; i++)
{
bh[i]->b_this_page = bh[(i + 1) % sectors]; // create circular
list
bh[i]->b_state = 0;
bh[i]->b_next_free = NULL;
bh[i]->b_count = 0;
bh[i]->b_size = 512;
bh[i]->b_data = (char *)&Sector[i * bps];
bh[i]->b_list = BUF_CLEAN;
bh[i]->b_dev = (int)NWDisk->PhysicalDiskHandle;
bh[i]->b_blocknr = (StartingLBA + i);
bh[i]->b_count = 1;
bh[i]->b_flushtime = 0;
set_bit(BH_Uptodate, &bh[i]->b_state);
set_bit(BH_Dirty, &bh[i]->b_state);
}
ll_rw_block(WRITEA, sectors, bh);
for (i=0; i < sectors; i++)
{
wait_on_buffer(bh[i]);
if (buffer_uptodate(bh[i]))
bytesWritten += bps;
else
write_error = 1;
put_bh(bh[i]);
}
return (write_error ? 0 : bytesWritten);
}
ULONG pZeroFillDiskSectors(ULONG disk, ULONG StartingLBA, ULONG sectors,
ULONG readAhead)
{
register ULONG i, j, bytesWritten = 0;
register ULONG bps;
register ULONG write_error = 0;
register NWDISK *NWDisk;
struct buffer_head *bh[sectors];
NWDisk = SystemDisk[disk];
bps = NWDisk->BytesPerSector;
for (i=0; i < sectors; i++)
{
bh[i] = get_bh();
if (!bh[i])
{
for (j=0; j < i; j++)
if (bh[j])
put_bh(bh[j]);
return 0;
}
}
for (i=0; i < sectors; i++)
{
bh[i]->b_this_page = bh[(i + 1) % sectors]; // create circular
list
bh[i]->b_state = 0;
bh[i]->b_next_free = NULL;
bh[i]->b_count = 0;
bh[i]->b_size = 512;
bh[i]->b_data = (char *) ZeroBuffer;
bh[i]->b_list = BUF_CLEAN;
bh[i]->b_dev = (int)NWDisk->PhysicalDiskHandle;
bh[i]->b_blocknr = (StartingLBA + i);
bh[i]->b_count = 1;
bh[i]->b_flushtime = 0;
set_bit(BH_Uptodate, &bh[i]->b_state);
set_bit(BH_Dirty, &bh[i]->b_state);
}
ll_rw_block(WRITEA, sectors, bh);
for (i=0; i < sectors; i++)
{
wait_on_buffer(bh[i]);
if (buffer_uptodate(bh[i]))
bytesWritten += bps;
else
write_error = 1;
put_bh(bh[i]);
}
return (write_error ? 0 : bytesWritten);
}
#endif
void SyncDevice(ULONG disk)
{
sync_dev((int)disk);
return;
}
ULONG ReadDiskSectors(ULONG disk, ULONG LBA, BYTE *Sector,
ULONG sectors, ULONG readAhead)
{
return (pReadDiskSectors(disk, LBA, Sector, sectors, readAhead));
}
ULONG WriteDiskSectors(ULONG disk, ULONG LBA, BYTE *Sector,
ULONG sectors, ULONG readAhead)
{
return (pWriteDiskSectors(disk, LBA, Sector, sectors, readAhead));
}
ULONG ZeroFillDiskSectors(ULONG disk, ULONG StartingLBA,
ULONG sectors, ULONG readAhead)
{
return (pZeroFillDiskSectors(disk, StartingLBA, sectors,
readAhead));
}
#endif
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/
This archive was generated by hypermail 2b29 : Wed Feb 23 2000 - 21:00:28 EST