rendered paste bodydiff -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);