patch-2.4.13 linux/fs/buffer.c

Next file: linux/fs/devfs/util.c
Previous file: linux/fs/block_dev.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.12/linux/fs/buffer.c linux/fs/buffer.c
@@ -112,15 +112,16 @@
 		int dummy5;	/* unused */
 	} b_un;
 	unsigned int data[N_PARAM];
-} bdf_prm = {{30, 64, 64, 256, 5*HZ, 30*HZ, 60, 0, 0}};
+} bdf_prm = {{40, 0, 0, 0, 5*HZ, 30*HZ, 60, 0, 0}};
 
 /* These are the min and max parameter values that we will allow to be assigned */
 int bdflush_min[N_PARAM] = {  0,  10,    5,   25,  0,   1*HZ,   0, 0, 0};
 int bdflush_max[N_PARAM] = {100,50000, 20000, 20000,10000*HZ, 6000*HZ, 100, 0, 0};
 
-inline void unlock_buffer(struct buffer_head *bh)
+void unlock_buffer(struct buffer_head *bh)
 {
 	clear_bit(BH_Wait_IO, &bh->b_state);
+	clear_bit(BH_launder, &bh->b_state);
 	clear_bit(BH_Lock, &bh->b_state);
 	smp_mb__after_clear_bit();
 	if (waitqueue_active(&bh->b_wait))
@@ -480,10 +481,12 @@
 
 static __inline__ void __hash_unlink(struct buffer_head *bh)
 {
-	if (bh->b_pprev) {
-		if (bh->b_next)
-			bh->b_next->b_pprev = bh->b_pprev;
-		*(bh->b_pprev) = bh->b_next;
+	struct buffer_head **pprev = bh->b_pprev;
+	if (pprev) {
+		struct buffer_head *next = bh->b_next;
+		if (next)
+			next->b_pprev = pprev;
+		*pprev = next;
 		bh->b_pprev = NULL;
 	}
 }
@@ -506,16 +509,22 @@
 	size_buffers_type[blist] += bh->b_size;
 }
 
-static void __remove_from_lru_list(struct buffer_head * bh, int blist)
+static void __remove_from_lru_list(struct buffer_head * bh)
 {
-	if (bh->b_prev_free || bh->b_next_free) {
-		bh->b_prev_free->b_next_free = bh->b_next_free;
-		bh->b_next_free->b_prev_free = bh->b_prev_free;
-		if (lru_list[blist] == bh)
-			lru_list[blist] = bh->b_next_free;
-		if (lru_list[blist] == bh)
-			lru_list[blist] = NULL;
-		bh->b_next_free = bh->b_prev_free = NULL;
+	struct buffer_head *next = bh->b_next_free;
+	if (next) {
+		struct buffer_head *prev = bh->b_prev_free;
+		int blist = bh->b_list;
+
+		prev->b_next_free = next;
+		next->b_prev_free = prev;
+		if (lru_list[blist] == bh) {
+			if (next == bh)
+				next = NULL;
+			lru_list[blist] = next;
+		}
+		bh->b_next_free = NULL;
+		bh->b_prev_free = NULL;
 		nr_buffers_type[blist]--;
 		size_buffers_type[blist] -= bh->b_size;
 	}
@@ -526,7 +535,7 @@
 static void __remove_from_queues(struct buffer_head *bh)
 {
 	__hash_unlink(bh);
-	__remove_from_lru_list(bh, bh->b_list);
+	__remove_from_lru_list(bh);
 }
 
 struct buffer_head * get_hash_table(kdev_t dev, int block, int size)
@@ -1095,7 +1104,7 @@
 	if (buffer_dirty(bh))
 		dispose = BUF_DIRTY;
 	if (dispose != bh->b_list) {
-		__remove_from_lru_list(bh, bh->b_list);
+		__remove_from_lru_list(bh);
 		bh->b_list = dispose;
 		if (dispose == BUF_CLEAN)
 			remove_inode_queue(bh);
@@ -1123,13 +1132,12 @@
 }
 
 /*
- * bforget() is like brelse(), except it puts the buffer on the
- * free list if it can.. We can NOT free the buffer if:
- *  - there are other users of it
- *  - it is locked and thus can have active IO
+ * bforget() is like brelse(), except it discards any
+ * potentially dirty data.
  */
 void __bforget(struct buffer_head * buf)
 {
+	mark_buffer_clean(buf);
 	__brelse(buf);
 }
 
@@ -1422,10 +1430,7 @@
 		mark_buffer_clean(old_bh);
 		wait_on_buffer(old_bh);
 		clear_bit(BH_Req, &old_bh->b_state);
-		/* Here we could run brelse or bforget. We use
-		   bforget because it will try to put the buffer
-		   in the freelist. */
-		__bforget(old_bh);
+		__brelse(old_bh);
 	}
 }
 
@@ -2327,29 +2332,40 @@
 	return 1;
 }
 
-static int sync_page_buffers(struct buffer_head *bh, unsigned int gfp_mask)
+static int sync_page_buffers(struct buffer_head *head, unsigned int gfp_mask)
 {
-	struct buffer_head * p = bh;
-	int tryagain = 1;
+	struct buffer_head * bh = head;
+	int tryagain = 0;
 
 	do {
-		if (buffer_dirty(p) || buffer_locked(p)) {
-			if (test_and_set_bit(BH_Wait_IO, &p->b_state)) {
-				if (buffer_dirty(p)) {
-					ll_rw_block(WRITE, 1, &p);
-					tryagain = 0;
-				} else if (buffer_locked(p)) {
-					if (gfp_mask & __GFP_WAITBUF) {
-						wait_on_buffer(p);
-						tryagain = 1;
-					} else
-						tryagain = 0;
-				}
-			} else
-				tryagain = 0;
+		if (!buffer_dirty(bh) && !buffer_locked(bh))
+			continue;
+
+		/* Don't start IO first time around.. */
+		if (!test_and_set_bit(BH_Wait_IO, &bh->b_state))
+			continue;
+
+		/* Second time through we start actively writing out.. */
+		if (test_and_set_bit(BH_Lock, &bh->b_state)) {
+			if (!test_bit(BH_launder, &bh->b_state))
+				continue;
+			wait_on_buffer(bh);
+			tryagain = 1;
+			continue;
+		}
+
+		if (!atomic_set_buffer_clean(bh)) {
+			unlock_buffer(bh);
+			continue;
 		}
-		p = p->b_this_page;
-	} while (p != bh);
+
+		__mark_buffer_clean(bh);
+		get_bh(bh);
+		set_bit(BH_launder, &bh->b_state);
+		bh->b_end_io = end_buffer_io_sync;
+		submit_bh(WRITE, bh);
+		tryagain = 0;
+	} while ((bh = bh->b_this_page) != head);
 
 	return tryagain;
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)