diff -Naur linux-2.6.10/drivers/block/aggregate.c linux-2.6.10-patched/drivers/block/aggregate.c
--- linux-2.6.10/drivers/block/aggregate.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.10-patched/drivers/block/aggregate.c	2005-02-16 16:13:29.000000000 -0500
@@ -0,0 +1,263 @@
+/*
+ *  FS aggregate statistics module.
+ *  Copyright (c) 2005 SUNY at Stony Brook
+ *  Copyright (c) 2005 Nikolai Joukov and Erez Zadok
+ */
+
+#include <linux/config.h> 
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+#define NEED_DESCRIPTIVE_MESSAGES
+#include "aggregate.h"
+/* Must be a power of two. */
+/* 32L << 32 cycles should be enough even for VERY slow FSs :-) */
+#define MAX_DISTR_DIGIT 32
+/* XXX: Should be a dynamic parameter */
+/* set to 0 to have no timeline and just the totals */
+#define MAX_DISTR_TIME 0
+
+/* This whole structure is smaller than 4K if MAX_DISTR_TIME = 0 */
+struct aggregate_pd {
+	unsigned long opcounts[OP_MAX];
+	unsigned long long init_cycle;
+	unsigned long long tot_cycles[OP_MAX];
+	struct proc_dir_entry *aggregate_proc_root;
+	unsigned long distribution[OP_MAX][MAX_DISTR_TIME + 1][MAX_DISTR_DIGIT + 1];
+};
+
+/* For now just use a static variable. */
+static struct aggregate_pd* this = NULL;
+static int called = 0;
+
+#define INIT_CYCLE (context->init_cycle)
+
+static void aggregate_stat_reset(void)
+{
+	memset(this, 0, sizeof(struct aggregate_pd));
+	RDTSC(this->init_cycle);
+}
+
+#define PROC_NAME "block_aggregate_stats"
+
+#define ADD_TO_BUFFER(str) \
+	do { \
+		char* tmp; \
+		len = strlen((str)); \
+		if (file->f_pos < total + len) { \
+			if (count < done + len) { \
+				len = count - done; \
+			} \
+			if (total < file->f_pos) { \
+				len -= file->f_pos - total;\
+				tmp = (str) + file->f_pos - total; \
+			} else {\
+				tmp = (str); \
+			} \
+			if (copy_to_user(buf, tmp, len)) { \
+				done = -EFAULT; \
+				goto out; \
+			} \
+			buf+= len; \
+			done+= len; \
+			if (count == done) \
+				goto out; \
+		} \
+		total+= len; \
+	} while(0);
+
+
+static inline char *op_to_str(int type)
+{
+        int i;
+        for (i = 0; msg_desc[i].str_type != NULL; i++) {
+                if (type == msg_desc[i].msg_type)
+                        return msg_desc[i].str_type;
+        }
+        return "MSG_UNKNOWN";
+}
+
+static ssize_t aggregate_proc_read(struct file *file, char *buf, size_t count, loff_t *ppos) {
+	char localbuf[1024];
+	int len, done = 0, total = 0;
+
+	unsigned int i, ii, iii, last_tick;
+	unsigned long long now;
+
+	RDTSC(now);
+	now -= this->init_cycle;
+	last_tick = (unsigned int)(now >> 32);
+	if (last_tick > MAX_DISTR_TIME)
+		last_tick = MAX_DISTR_TIME;
+	
+	for (i = 0; i < OP_MAX; i++) {
+		if (this->opcounts[i] > 0) {
+			ADD_TO_BUFFER(op_to_str(i));
+			sprintf(localbuf, " %lu %llu\n", this->opcounts[i], this->tot_cycles[i]);
+			ADD_TO_BUFFER(localbuf);
+			for (ii = 0; ii < last_tick + 1; ii++) {
+				for (iii = 0; iii < MAX_DISTR_DIGIT + 1; iii++) {
+					sprintf(localbuf, " %lu", this->distribution[i][ii][iii]);
+					ADD_TO_BUFFER(localbuf);
+				}
+				ADD_TO_BUFFER("\n");
+			}
+		}
+	}
+out:
+	if (done > 0) {
+		file->f_pos += done;
+		ppos[0] += done;
+	}
+	return done;
+}
+
+static ssize_t aggregate_proc_write(struct file *file, const char *buf, size_t count, loff_t *ppos) {
+	aggregate_stat_reset();
+	return count;
+}
+
+struct file_operations proc_aggregate_file_operations = {
+	read: aggregate_proc_read,
+	write: aggregate_proc_write
+};
+
+static int aggregate_proc_create(void)
+{
+        struct proc_dir_entry *proc_de;
+	int err = 0;
+
+	/*x_proc_root = create_proc_entry(PROC_NAME, S_IFDIR, NULL);
+	if (!x_proc_root) {
+   	#ifdef PRINT_DEBUG_MESSAGES
+		printk(KERN_ERR "Adding x to proc failed\n");
+	#endif   
+		result = -EPERM;
+		goto out;
+	}
+	x_proc_root->owner = THIS_MODULE;*/
+        
+        proc_de = create_proc_entry(PROC_NAME, 0, NULL);
+        if (!proc_de) {
+   		#ifdef PRINT_DEBUG_MESSAGES
+			printk(KERN_ERR "Adding proc entry failed\n");
+		#endif
+			goto out;
+        }
+        proc_de->owner = THIS_MODULE;
+        proc_de->data = (void *)this;
+        proc_de->proc_fops = &proc_aggregate_file_operations;
+out:
+	return err;
+}
+
+static void aggregate_proc_destroy(void)
+{
+	//remove_proc_entry(stopd(sb)->proc_name, x_proc_root);
+	remove_proc_entry(PROC_NAME, NULL);
+}
+
+
+
+int aggregate_init(void)
+{
+	int err = -ENOMEM;
+#if (MAX_DISTR_TIME > 0)
+	this = vmalloc(sizeof(struct aggregate_pd));
+#else
+	this = kmalloc(sizeof(struct aggregate_pd), GFP_KERNEL);
+#endif
+	if (!this)
+		goto out;
+
+	aggregate_stat_reset();
+    
+	err = aggregate_proc_create();
+    
+out: 
+	return err; 
+}
+
+void aggregate_release(void)
+{
+	aggregate_proc_destroy();
+    
+	if (this) {
+#if (MAX_DISTR_TIME > 0)
+		vfree(this);
+#else
+		kfree(this);
+#endif
+		this = NULL;
+	}
+}
+
+void aggregate_pre(int op, struct aggregate_context* context)
+{
+	if(!called) {
+		aggregate_init();
+		called=1;
+	}
+	if(!this || !context){
+		return;
+	}	
+	this->opcounts[(op)]++;
+	RDTSC(INIT_CYCLE);
+}
+
+void aggregate_post_slow(int op, struct aggregate_context* context)
+{
+	unsigned long long l;
+	RDTSC(l);
+	unsigned long long delay;
+	unsigned long long ll;
+	int i, ii;
+	
+	if(!this || !context) {
+		return;
+	}
+	delay = (l - INIT_CYCLE);
+	this->tot_cycles[(op)] += delay;
+	
+	ll = 32L;
+	for (i = 0; i < MAX_DISTR_DIGIT; i++) {
+		if (delay < ll)
+			break;
+		ll = ll << 1;
+	}
+	
+	ii = (int)((l - this->init_cycle) >> 32);
+	if (ii > MAX_DISTR_TIME)
+		ii = MAX_DISTR_TIME;
+	this->distribution[(op)][ii][i]++;
+}
+
+void aggregate_post(int op, struct aggregate_context* context)
+{
+	unsigned long long l;
+	RDTSC(l);
+	unsigned long long ll_delay;
+	unsigned int i, ii, iii, i_delay;
+
+	if(!this || !context) {
+		return;
+	}
+	ll_delay = (l - INIT_CYCLE);
+
+	this->tot_cycles[(op)] += ll_delay;
+
+	iii = 1;
+	i_delay = (unsigned int)(ll_delay >> 5);
+	for (i = 0; i < MAX_DISTR_DIGIT; i++) {
+		if (i_delay < iii)
+			break;
+		iii <<= 1;
+	}
+	ii = (int)((l - this->init_cycle) >> 32);
+	if (ii > MAX_DISTR_TIME)
+		ii = MAX_DISTR_TIME;
+	this->distribution[(op)][ii][i]++;
+}
diff -Naur linux-2.6.10/drivers/block/aggregate.h linux-2.6.10-patched/drivers/block/aggregate.h
--- linux-2.6.10/drivers/block/aggregate.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.10-patched/drivers/block/aggregate.h	2005-02-13 19:39:07.000000000 -0500
@@ -0,0 +1,33 @@
+#ifndef _AGGREGATE_H_
+#define _AGGREGATE_H_
+
+#include "messages.h"
+//#include "generics.h"
+//#define PRINT_DEBUG_MESSAGES
+
+struct aggregate_context {
+    unsigned long long init_cycle;
+};
+
+int  aggregate_init(void);
+void aggregate_release(void);
+
+void aggregate_pre(int op, struct aggregate_context* context);
+void aggregate_post(int op, struct aggregate_context* context);
+
+#define AGGREGATE_PRE(op,context) \
+	aggregate_pre(op, context);
+
+#define AGGREGATE_POST(op,context) \
+	aggregate_post(op, context);
+
+#define RDTSC(qp) \
+	do { \
+		unsigned long lowPart, highPart; \
+		__asm__ __volatile__("rdtsc" : "=a" (lowPart), "=d" (highPart)); \
+		qp = (((unsigned long long) highPart) << 32) | lowPart; \
+	} while (0);
+
+
+
+#endif
diff -Naur linux-2.6.10/drivers/block/ll_rw_blk.c linux-2.6.10-patched/drivers/block/ll_rw_blk.c
--- linux-2.6.10/drivers/block/ll_rw_blk.c	2004-12-24 16:33:59.000000000 -0500
+++ linux-2.6.10-patched/drivers/block/ll_rw_blk.c	2005-02-16 16:17:03.000000000 -0500
@@ -28,11 +28,11 @@
 #include <linux/slab.h>
 #include <linux/swap.h>
 #include <linux/writeback.h>
-
 /*
  * for max sense size
  */
 #include <scsi/scsi_cmnd.h>
+#include "../block/aggregate.h"
 
 static void blk_unplug_work(void *data);
 static void blk_unplug_timeout(unsigned long data);
@@ -2723,7 +2723,8 @@
 			(unsigned long long)bio->bi_sector,
 			bdevname(bio->bi_bdev,b));
 	}
-
+// Initialize the aggregate engine here
+	AGGREGATE_PRE(rw,&bio->aggr_context);
 	generic_make_request(bio);
 }
 
diff -Naur linux-2.6.10/drivers/block/Makefile linux-2.6.10-patched/drivers/block/Makefile
--- linux-2.6.10/drivers/block/Makefile	2004-12-24 16:35:24.000000000 -0500
+++ linux-2.6.10-patched/drivers/block/Makefile	2005-02-13 20:07:14.000000000 -0500
@@ -13,7 +13,7 @@
 # kblockd threads
 #
 
-obj-y	:= elevator.o ll_rw_blk.o ioctl.o genhd.o scsi_ioctl.o
+obj-y	:= elevator.o ll_rw_blk.o ioctl.o genhd.o scsi_ioctl.o aggregate.o
 
 obj-$(CONFIG_IOSCHED_NOOP)	+= noop-iosched.o
 obj-$(CONFIG_IOSCHED_AS)	+= as-iosched.o
diff -Naur linux-2.6.10/drivers/block/messages.h linux-2.6.10-patched/drivers/block/messages.h
--- linux-2.6.10/drivers/block/messages.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.10-patched/drivers/block/messages.h	2005-02-13 19:48:49.000000000 -0500
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1997-2005 Erez Zadok
+ * Copyright (c) 2002-2005 Akshat Aranya
+ * Copyright (c) 2001-2005 Stony Brook University
+ *
+ * For specific licensing information, see the COPYING file distributed with
+ * this package, or get one from ftp://ftp.filesystems.org/pub/fist/COPYING.
+ *
+ * This Copyright notice must be kept intact and distributed with all
+ * fistgen sources INCLUDING sources generated by fistgen.
+ */
+/*
+ * messages.h:
+ * This file defines the message types for the
+ * trace messages. Also defines the constants for
+ * file system operations.
+ */
+
+#ifndef __MESSAGES_H
+#define __MESSAGES_H
+
+typedef unsigned short op_t;
+#define OP_BASE         0
+#define OP_BLOCK_READ            (OP_BASE + 0)
+#define OP_BLOCK_WRITE           (OP_BASE + 1)
+#define OP_BLOCK_READA           (OP_BASE + 2)
+#define OP_MAX          		   4 
+
+#define MSG_ENTRY(M) { M, #M }
+
+struct msg_desc_t {
+	op_t msg_type;
+	char *str_type;
+};
+
+#ifdef NEED_DESCRIPTIVE_MESSAGES
+
+struct msg_desc_t msg_desc[] = {
+	MSG_ENTRY(OP_BLOCK_READ),
+	MSG_ENTRY(OP_BLOCK_WRITE),
+	MSG_ENTRY(OP_BLOCK_READA)
+};
+
+#else
+extern struct msg_desc_t msg_desc[];
+
+#endif 
+
+#endif /* __MESSAGES_H */
diff -Naur linux-2.6.10/fs/bio.c linux-2.6.10-patched/fs/bio.c
--- linux-2.6.10/fs/bio.c	2004-12-24 16:35:00.000000000 -0500
+++ linux-2.6.10-patched/fs/bio.c	2005-02-13 19:39:53.000000000 -0500
@@ -25,7 +25,7 @@
 #include <linux/module.h>
 #include <linux/mempool.h>
 #include <linux/workqueue.h>
-
+#include "../drivers/block/aggregate.h"
 #define BIO_POOL_SIZE 256
 
 static mempool_t *bio_pool;
@@ -827,7 +827,7 @@
 
 	bio->bi_size -= bytes_done;
 	bio->bi_sector += (bytes_done >> 9);
-
+	AGGREGATE_POST(bio_rw(bio),&bio->aggr_context);
 	if (bio->bi_end_io)
 		bio->bi_end_io(bio, bytes_done, error);
 }
diff -Naur linux-2.6.10/include/linux/bio.h linux-2.6.10-patched/include/linux/bio.h
--- linux-2.6.10/include/linux/bio.h	2004-12-24 16:35:24.000000000 -0500
+++ linux-2.6.10-patched/include/linux/bio.h	2005-02-13 19:48:27.000000000 -0500
@@ -62,7 +62,7 @@
 struct bio;
 typedef int (bio_end_io_t) (struct bio *, unsigned int, int);
 typedef void (bio_destructor_t) (struct bio *);
-
+#include "../../drivers/block/aggregate.h"
 /*
  * main unit of I/O for the block layer and lower layers (ie drivers and
  * stacking drivers)
@@ -109,6 +109,7 @@
 	void			*bi_private;
 
 	bio_destructor_t	*bi_destructor;	/* destructor */
+	struct aggregate_context aggr_context;
 };
 
 /*
