patch-1.3.90 linux/fs/buffer.c
Next file: linux/fs/dquot.c
Previous file: linux/drivers/scsi/sd.c
Back to the patch index
Back to the overall index
- Lines: 198
- Date:
Tue Apr 16 15:43:19 1996
- Orig file:
v1.3.89/linux/fs/buffer.c
- Orig date:
Mon Apr 15 12:20:20 1996
diff -u --recursive --new-file v1.3.89/linux/fs/buffer.c linux/fs/buffer.c
@@ -803,6 +803,10 @@
}
+/*
+ * A buffer may need to be moved from one buffer list to another
+ * (e.g. in case it is not shared any more). Handle this.
+ */
void refile_buffer(struct buffer_head * buf)
{
int dispose;
@@ -1088,6 +1092,46 @@
return NULL;
}
+/* Run the hooks that have to be done when a page I/O has completed. */
+static inline void after_unlock_page (struct page * page)
+{
+ if (clear_bit(PG_decr_after, &page->flags))
+ nr_async_pages--;
+ if (clear_bit(PG_free_after, &page->flags))
+ free_page(page_address(page));
+ if (clear_bit(PG_swap_unlock_after, &page->flags))
+ swap_after_unlock_page(page->swap_unlock_entry);
+}
+
+/* Free all temporary buffers belonging to a page. */
+static inline void free_async_buffers (struct buffer_head * bh)
+{
+ struct buffer_head * tmp;
+ unsigned long flags;
+
+ tmp = bh;
+ save_flags(flags);
+ cli();
+ 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);
+}
+
+/*
+ * Start I/O on a page.
+ * This function expects the page to be locked and may return before I/O is complete.
+ * You then have to check page->locked, page->uptodate, and maybe wait on page->wait.
+ */
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];
@@ -1095,10 +1139,20 @@
struct page *page;
page = mem_map + MAP_NR(address);
+ if (!PageLocked(page))
+ panic("brw_page: page not locked for I/O");
clear_bit(PG_uptodate, &page->flags);
+ /*
+ * Allocate buffer heads pointing to this page, just for I/O.
+ * They do _not_ show up in the buffer hash table!
+ * They are _not_ registered in page->buffers either!
+ */
bh = create_buffers(address, size);
- if (!bh)
+ if (!bh) {
+ clear_bit(PG_locked, &page->flags);
+ wake_up(&page->wait);
return -ENOMEM;
+ }
nr = 0;
next = bh;
do {
@@ -1148,33 +1202,32 @@
} while (prev = next, (next = next->b_this_page) != NULL);
prev->b_this_page = bh;
- if (nr)
+ if (nr) {
ll_rw_block(rw, nr, arr);
- else {
- unsigned long flags;
+ /* The rest of the work is done in mark_buffer_uptodate()
+ * and unlock_buffer(). */
+ } else {
clear_bit(PG_locked, &page->flags);
set_bit(PG_uptodate, &page->flags);
wake_up(&page->wait);
- next = bh;
- save_flags(flags);
- cli();
- do {
- next->b_next_free = reuse_list;
- reuse_list = next;
- next = next->b_this_page;
- } while (next != bh);
- restore_flags(flags);
+ free_async_buffers(bh);
+ after_unlock_page(page);
}
++current->maj_flt;
return 0;
}
+/*
+ * This is called by end_request() when I/O has completed.
+ */
void mark_buffer_uptodate(struct buffer_head * bh, int on)
{
if (on) {
struct buffer_head *tmp = bh;
int page_uptodate = 1;
set_bit(BH_Uptodate, &bh->b_state);
+ /* If a page has buffers and all these buffers are uptodate,
+ * then the page is uptodate. */
do {
if (!test_bit(BH_Uptodate, &tmp->b_state)) {
page_uptodate = 0;
@@ -1188,10 +1241,12 @@
clear_bit(BH_Uptodate, &bh->b_state);
}
+/*
+ * This is called by end_request() when I/O has completed.
+ */
void unlock_buffer(struct buffer_head * bh)
{
struct buffer_head *tmp;
- unsigned long flags;
struct page *page;
clear_bit(BH_Lock, &bh->b_state);
@@ -1199,6 +1254,7 @@
if (!test_bit(BH_FreeOnIO, &bh->b_state))
return;
+ /* This is a temporary buffer used for page I/O. */
page = mem_map + MAP_NR(bh->b_data);
if (!PageLocked(page)) {
printk ("Whoops: unlock_buffer: "
@@ -1218,31 +1274,11 @@
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);
+ /* OK, the async IO on this page is complete. */
clear_bit(PG_locked, &page->flags);
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 (clear_bit(PG_freeafter, &page->flags)) {
- extern int nr_async_pages;
- nr_async_pages--;
- free_page(page_address(page));
- }
+ free_async_buffers(bh);
+ after_unlock_page(page);
wake_up(&buffer_wait);
}
@@ -1262,6 +1298,7 @@
address = page_address(page);
page->count++;
set_bit(PG_locked, &page->flags);
+ set_bit(PG_free_after, &page->flags);
i = PAGE_SIZE >> inode->i_sb->s_blocksize_bits;
block = page->offset >> inode->i_sb->s_blocksize_bits;
@@ -1275,7 +1312,6 @@
/* IO start */
brw_page(READ, address, inode->i_dev, nr, inode->i_sb->s_blocksize, 1);
- free_page(address);
return 0;
}
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