All pastes #181517 Raw Edit

Something

public text v1 · immutable
#181517 ·published 2006-09-25 01:11 UTC
rendered paste body
diff -U 3 -H -b -w -B -E -d -p -r -N -- linux-2.6.18/mm/filemap.c linux-2.6.18-ar7/mm/filemap.c
--- linux-2.6.18/mm/filemap.c	2006-09-20 13:07:04.000000000 +0200
+++ linux-2.6.18-ar7/mm/filemap.c	2006-09-20 17:28:27.000000000 +0200
@@ -33,6 +33,176 @@
 #include "filemap.h"
 #include "internal.h"
 
+/******************************************************************************
+ * <<<< 20060608 =OS= -- sync-on-demand
+ ******************************************************************************/
+
+#include <asm/atomic.h>
+
+/*
+ * __atomic_xchg - read and set atomic variable
+ * @v: pointer of type atomic_t
+ * @i: required value
+ *
+ * (as introduced in 2.6.16, 20060608 =OS=)
+ */
+#define __atomic_xchg(v, i)		(xchg(&((v)->counter), i))
+
+#define	CONFIG_MAX_DIRTY_FILE_PAGES	40	/* <<<< see generic_file_aio_write() */
+#define	CONFIG_MAX_DIRTY_FILE_PAGES_2	10	/* <<<< see generic_file_aio_write() */
+#define	CONFIG_MAX_DIRTY_REST_PAGES     20	/* <<<< see fs/open.c, filp_close() */
+#define	CONFIG_FILE_SYNC_THRESHOLD	2048	/* kBytes (obsolete) */
+#define	CONFIG_FILE_SYNC_MULTIPLIER	3	/* File sync threshold (sync <-> async): */
+#define	CONFIG_FILE_SYNC_DIVISOR	2	/*   (pages_min*multiplier)/divisor */
+
+#define	K(x)				((x) << (PAGE_SHIFT - 10))
+
+typedef struct {
+	
+	const char *	name;		/* Name of /proc writable parameter */
+	unsigned *	var;		/* Pointer to its unsigned variable */
+	atomic_t *	dirty;		/* Pointer to its atomic update flag */
+} entry_t, * entry_p; 
+
+atomic_t	flag_file_sync		= ATOMIC_INIT(1);	/* Safety first: Let's start in sync mode */
+atomic_t	f_global_dirt		= ATOMIC_INIT(0);
+unsigned	max_rest_dirty_pages	= CONFIG_MAX_DIRTY_REST_PAGES;
+unsigned	max_file_dirty_pages	= CONFIG_MAX_DIRTY_FILE_PAGES;
+unsigned	max_file_dirty_pages2	= CONFIG_MAX_DIRTY_FILE_PAGES_2;
+unsigned	file_sync_page_mul	= CONFIG_FILE_SYNC_MULTIPLIER;
+unsigned	file_sync_page_div	= CONFIG_FILE_SYNC_DIVISOR;
+atomic_t	file_sync_dirty		= ATOMIC_INIT(1);
+
+static entry_t	varray[] = {
+#define	ENTRY(x,f)			{#x,&x,f}
+	
+	ENTRY(max_rest_dirty_pages,	NULL),
+	ENTRY(max_file_dirty_pages,	NULL),
+	ENTRY(max_file_dirty_pages2,	NULL),
+	ENTRY(file_sync_page_mul,	&file_sync_dirty),
+	ENTRY(file_sync_page_div,	&file_sync_dirty)
+
+#undef	ENTRY
+} ;
+#define	NUM_ENTRIES			(sizeof(varray)/sizeof(varray[0]))
+
+static inline unsigned min_threshold(void) {
+	unsigned	nmp = K(nr_min_pages());
+
+	return (nmp * file_sync_page_mul) / file_sync_page_div;
+} /* min_threshold */
+
+int file_io_controller (void) {
+	static unsigned	file_sync_threshold;
+	int		flag;
+
+	if (__atomic_xchg (&file_sync_dirty, 0))
+		file_sync_threshold = min_threshold ();
+	flag = K(nr_free_pages ()) < file_sync_threshold;
+	atomic_set (&flag_file_sync, flag);
+/*
+ *	if (flag != __atomic_xchg (&flag_file_sync, flag)) {
+ *		printk (KERN_INFO "<<<< Now %s mode >>>>\n", flag ? "sync" : "async");
+ *	}
+ */ 
+	return flag;
+} /* file_io_controller */
+
+/*----------------------------------------------------------------------------*/
+#if defined (CONFIG_PROC_FS)
+#include <linux/proc_fs.h>
+
+static struct proc_dir_entry	* proc_file = NULL;
+
+static void sod_var_assign (entry_p ep, char * valp) {
+	unsigned	val = 0;
+	char *		vp = valp;
+	char *		cp;
+
+	while ((*vp == ' ') || (*vp == '\t'))
+		++vp;
+	cp = vp; 
+	do {
+		if ((*vp < '0') || ('9' < *vp)) break;
+		val = val * 10 + (*vp - '0');
+	} while (*++vp != '\0');
+	if ((*vp != ' ') && (*vp != '\t') && (*vp != '\n') && (*vp != '\0')) {
+		printk (KERN_INFO "Invalid number format (%s)!\n", ep->name);
+		return;
+	}
+	/* printk (KERN_INFO "/proc/sync-on-demand.%s: %u --> %u\n", ep->name, *(ep->var), val); */
+	*(ep->var) = val;
+	if (ep->dirty != NULL)
+		atomic_set (ep->dirty, 1);
+} /* sod_var_assign */
+
+static int sod_read (char * buf, char ** start, off_t offset, int size, int * eof, void * data) {
+	int	bytes_written	= 0;
+	int	ret, i;
+
+	/* read/write variables/values: */
+	for (i = 0; i < NUM_ENTRIES; i++) {
+		ret = snprintf (
+			buf + bytes_written, (size - bytes_written), 
+			"%-30s%u\n",
+			varray[i].name, *(varray[i].var)
+			);
+		bytes_written += (ret > (size - bytes_written)) ? (size - bytes_written) : ret;
+	}
+
+	/* read-only variables/values: */
+	ret = snprintf (
+		buf + bytes_written, (size - bytes_written), 
+		"%-30s%u kB\n",
+		"(file_sync_threshold)", min_threshold ()
+		);
+	bytes_written += (ret > (size - bytes_written)) ? (size - bytes_written) : ret;
+
+	*eof = 1;
+	return bytes_written;
+} /* sod_read */
+
+static ssize_t sod_write (struct file * filp, const char __user * buf, unsigned long count, void * data) {
+	char *		kbuf;
+	unsigned long	not_copied;
+	int		i, l;
+	
+	if (NULL == (kbuf = kmalloc (count + 1, GFP_KERNEL)))
+		return -ENOMEM;
+	kbuf[count] = (char) 0;
+	not_copied = copy_from_user (kbuf, buf, count);
+	for (i = 0; i < NUM_ENTRIES; i++) {
+		l = strlen (varray[i].name);
+		if (l >= count) continue;
+		if (0 == strncmp (kbuf, varray[i].name, l)) {
+			if (kbuf[l] != ' ') continue;
+			sod_var_assign (&varray[i], &kbuf[l]);
+			break;
+		}
+	}
+	kfree (kbuf);
+	return (count - not_copied);
+} /* sod_write */
+
+void setup_sod_procfs (void) {
+
+	proc_file = create_proc_entry ("sync-on-demand", S_IRUSR|S_IWUSR, NULL);
+	if (proc_file == NULL) return;
+	proc_file->read_proc	= sod_read;
+	proc_file->write_proc	= sod_write;
+	proc_file->data		= NULL;
+} /* setup_procfs */
+
+void shutdown_sod_procfs (void) {
+
+	if (proc_file != NULL)
+		remove_proc_entry ("sync-on-demand", NULL);
+} /* shutdown_procfs */
+#endif
+
+/******************************************************************************/
+
+
 /*
  * FIXME: remove all knowledge of the buffer layer from the core VM
  */
@@ -2077,6 +2247,9 @@ generic_file_buffered_write(struct kiocb
 	size_t		iov_base = 0;	   /* offset in the current iovec */
 	char __user	*buf;
 
+	unsigned long pnd;		/* <<<< 20060608 =OS= */
+	struct page_state ps;
+	
 	pagevec_init(&lru_pvec, 0);
 
 	/*
@@ -2089,6 +2262,10 @@ generic_file_buffered_write(struct kiocb
 		buf = cur_iov->iov_base + iov_base;
 	}
 
+	/* <<<< 20060608 =OS= */
+	get_page_state (&ps);	
+	pnd = ps.nr_dirty;
+
 	do {
 		unsigned long index;
 		unsigned long offset;
@@ -2214,6 +2392,13 @@ zero_length_segment:
 		status = filemap_write_and_wait(mapping);
 
 	pagevec_lru_add(&lru_pvec);
+	
+	get_page_state (&ps);		/* <<<< 20060608 =OS= */
+	if (ps.nr_dirty > pnd) {
+		file->f_dirt += ps.nr_dirty - pnd;
+	}
+	file_io_controller();
+
 	return written ? written : status;
 }
 EXPORT_SYMBOL(generic_file_buffered_write);
@@ -2354,11 +2539,26 @@ ssize_t generic_file_aio_write(struct ki
 	struct address_space *mapping = file->f_mapping;
 	struct inode *inode = mapping->host;
 	ssize_t ret;
+	int err, flag, limit;
 	struct iovec local_iov = { .iov_base = (void __user *)buf,
 					.iov_len = count };
 
 	BUG_ON(iocb->ki_pos != pos);
 
+	/* <<<< 20060602 =OS= */
+	flag = atomic_read(&flag_file_sync);
+	limit = flag ? max_file_dirty_pages2 : max_file_dirty_pages;
+	if (file->f_dirt > limit) {
+		if (flag) {
+			/* Synchronously writeback this file... */
+			err = file_fsync (file, file->f_dentry, 1);
+		}
+		wakeup_pdflush (0);
+		atomic_set (&f_global_dirt, 0);		/* Nothing but an asumption! :-) */
+		file->f_dirt = err = 0;			/* Ditto */
+	}
+	file_io_controller();
+
 	mutex_lock(&inode->i_mutex);
 	ret = __generic_file_aio_write_nolock(iocb, &local_iov, 1,
 						&iocb->ki_pos);