patch-1.3.59 linux/fs/buffer.c
Next file: linux/fs/proc/procfs_syms.c
Previous file: linux/drivers/sound/sb_dsp.c
Back to the patch index
Back to the overall index
- Lines: 192
- Date:
Tue Jan 23 20:47:33 1996
- Orig file:
v1.3.58/linux/fs/buffer.c
- Orig date:
Tue Jan 23 21:15:49 1996
diff -u --recursive --new-file v1.3.58/linux/fs/buffer.c linux/fs/buffer.c
@@ -998,13 +998,12 @@
unsigned long flags;
save_flags(flags);
- cli();
while (reuse_list) {
+ cli();
bh = reuse_list;
reuse_list = bh->b_next_free;
restore_flags(flags);
put_unused_buffer_head(bh);
- cli();
}
}
@@ -1062,7 +1061,7 @@
return NULL;
}
-static int bread_page(unsigned long address, kdev_t dev, int b[], int size)
+int brw_page(int rw, unsigned long address, kdev_t dev, int b[], int size, int bmap)
{
struct buffer_head *bh, *prev, *next, *arr[MAX_BUF_PER_PAGE];
int block, nr;
@@ -1085,35 +1084,55 @@
next->b_blocknr = block;
next->b_count = 1;
next->b_flushtime = 0;
- clear_bit(BH_Dirty, &next->b_state);
- clear_bit(BH_Req, &next->b_state);
set_bit(BH_Uptodate, &next->b_state);
-
- if (!block) {
+
+ /* When we use bmap, we define block zero to represent
+ a hole. ll_rw_page, however, may legitimately
+ access block zero, and we need to distinguish the
+ two cases.
+ */
+ if (bmap && !block) {
memset(next->b_data, 0, size);
+ next->b_count--;
continue;
}
tmp = get_hash_table(dev, block, size);
if (tmp) {
if (!buffer_uptodate(tmp)) {
- ll_rw_block(READ, 1, &tmp);
+ if (rw == READ)
+ ll_rw_block(READ, 1, &tmp);
wait_on_buffer(tmp);
}
- memcpy(next->b_data, tmp->b_data, size);
+ if (rw == READ)
+ memcpy(next->b_data, tmp->b_data, size);
+ else {
+ memcpy(tmp->b_data, next->b_data, size);
+ set_bit(BH_Dirty, &tmp->b_state);
+ }
brelse(tmp);
+ next->b_count--;
continue;
}
- clear_bit(BH_Uptodate, &next->b_state);
+ if (rw == READ)
+ clear_bit(BH_Uptodate, &next->b_state);
+ else
+ set_bit(BH_Dirty, &next->b_state);
arr[nr++] = next;
} while (prev = next, (next = next->b_this_page) != NULL);
prev->b_this_page = bh;
if (nr)
- ll_rw_block(READ, nr, arr);
+ ll_rw_block(rw, nr, arr);
else {
page->locked = 0;
page->uptodate = 1;
wake_up(&page->wait);
+ next = bh;
+ do {
+ next->b_next_free = reuse_list;
+ reuse_list = next;
+ next = next->b_this_page;
+ } while (next != bh);
}
++current->maj_flt;
return 0;
@@ -1138,6 +1157,64 @@
clear_bit(BH_Uptodate, &bh->b_state);
}
+void unlock_buffer(struct buffer_head * bh)
+{
+ struct buffer_head *tmp;
+ unsigned long flags;
+ struct page *page;
+
+ clear_bit(BH_Lock, &bh->b_state);
+ wake_up(&bh->b_wait);
+
+ if (!test_bit(BH_FreeOnIO, &bh->b_state))
+ return;
+ page = mem_map + MAP_NR(bh->b_data);
+ if (!page->locked) {
+ printk ("Whoops: unlock_buffer: "
+ "async io complete on unlocked page\n");
+ return;
+ }
+ if (bh->b_count != 1) {
+ printk ("Whoops: unlock_buffer: b_count != 1 on async io.\n");
+ return;
+ }
+ /* Async buffer_heads are here only as labels for IO, and get
+ thrown away once the IO for this page is complete. IO is
+ deemed complete once all buffers have been visited
+ (b_count==0) and are now unlocked. */
+ bh->b_count--;
+ for (tmp = bh; tmp=tmp->b_this_page, tmp!=bh; ) {
+ if (test_bit(BH_Lock, &tmp->b_state) || tmp->b_count)
+ return;
+ }
+
+ /* OK, go ahead and complete the async IO on this page. */
+ save_flags(flags);
+ page->locked = 0;
+ wake_up(&page->wait);
+ cli();
+ tmp = bh;
+ do {
+ if (!test_bit(BH_FreeOnIO, &tmp->b_state)) {
+ printk ("Whoops: unlock_buffer: "
+ "async IO mismatch on page.\n");
+ restore_flags(flags);
+ return;
+ }
+ tmp->b_next_free = reuse_list;
+ reuse_list = tmp;
+ clear_bit(BH_FreeOnIO, &tmp->b_state);
+ tmp = tmp->b_this_page;
+ } while (tmp != bh);
+ restore_flags(flags);
+ if (page->free_after) {
+ extern int nr_async_pages;
+ nr_async_pages--;
+ page->free_after = 0;
+ free_page(page_address(page));
+ }
+}
+
/*
* Generic "readpage" function for block devices that have the normal
* bmap functionality. This is most of the block device filesystems.
@@ -1167,37 +1244,10 @@
/* IO start */
page->count++;
address = page_address(page);
- bread_page(address, inode->i_dev, nr, inode->i_sb->s_blocksize);
+ brw_page(READ, address, inode->i_dev, nr, inode->i_sb->s_blocksize, 1);
free_page(address);
return 0;
}
-
-#if 0
-/*
- * bwrite_page writes a page out to the buffer cache and/or the physical device.
- * It's used for mmap writes (the same way bread_page() is used for mmap reads).
- */
-void bwrite_page(unsigned long address, kdev_t dev, int b[], int size)
-{
- struct buffer_head * bh[MAX_BUF_PER_PAGE];
- int i, j;
-
- for (i=0, j=0; j<PAGE_SIZE ; i++, j+= size) {
- bh[i] = NULL;
- if (b[i])
- bh[i] = getblk(dev, b[i], size);
- }
- for (i=0, j=0; j<PAGE_SIZE ; i++, j += size, address += size) {
- if (bh[i]) {
- memcpy(bh[i]->b_data, (void *) address, size);
- mark_buffer_uptodate(bh[i], 1);
- mark_buffer_dirty(bh[i], 0);
- brelse(bh[i]);
- } else
- memset((void *) address, 0, size); /* ???!?!! */
- }
-}
-#endif
/*
* Try to increase the number of buffers available: the size argument
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this