diff -Nru linux-2.5.74-uc0/fs/inode.c linux-2.5.x/fs/inode.c
--- linux-2.5.74-uc0/fs/inode.c	2003-07-02 22:57:36.000000000 +0200
+++ linux-2.5.x/fs/inode.c	2003-07-03 09:37:22.000000000 +0200
@@ -145,6 +145,12 @@
 		mapping->dirtied_when = 0;
 		mapping->assoc_mapping = NULL;
 		mapping->backing_dev_info = &default_backing_dev_info;
+
+#ifndef CONFIG_MMU
+		mapping->i_mmap_block = NULL;
+		mapping->i_mmap_cnt = 0;
+#endif /* !CONFIG_MMU */
+
 		if (sb->s_bdev)
 			mapping->backing_dev_info = sb->s_bdev->bd_inode->i_mapping->backing_dev_info;
 		memset(&inode->u, 0, sizeof(inode->u));
@@ -183,11 +189,13 @@
 	sema_init(&inode->i_sem, 1);
 	INIT_RADIX_TREE(&inode->i_data.page_tree, GFP_ATOMIC);
 	spin_lock_init(&inode->i_data.page_lock);
-	init_MUTEX(&inode->i_data.i_shared_sem);
 	INIT_LIST_HEAD(&inode->i_data.private_list);
 	spin_lock_init(&inode->i_data.private_lock);
+#ifdef CONFIG_MMU
 	INIT_LIST_HEAD(&inode->i_data.i_mmap);
 	INIT_LIST_HEAD(&inode->i_data.i_mmap_shared);
+	init_MUTEX(&inode->i_data.i_shared_sem);
+#endif /* CONFIG_MMU */
 	spin_lock_init(&inode->i_lock);
 }
 
diff -Nru linux-2.5.74-uc0/fs/locks.c linux-2.5.x/fs/locks.c
--- linux-2.5.74-uc0/fs/locks.c	2003-07-02 22:56:06.000000000 +0200
+++ linux-2.5.x/fs/locks.c	2003-07-03 09:37:22.000000000 +0200
@@ -1423,6 +1423,7 @@
 
 	inode = filp->f_dentry->d_inode;
 
+#ifdef CONFIG_MMU
 	/* Don't allow mandatory locks on files that may be memory mapped
 	 * and shared.
 	 */
@@ -1435,6 +1436,7 @@
 			goto out;
 		}
 	}
+#endif /* CONFIG_MMU */
 
 	error = flock_to_posix_lock(filp, file_lock, &flock);
 	if (error)
@@ -1561,6 +1563,7 @@
 
 	inode = filp->f_dentry->d_inode;
 
+#ifdef CONFIG_MMU
 	/* Don't allow mandatory locks on files that may be memory mapped
 	 * and shared.
 	 */
@@ -1573,6 +1576,7 @@
 			goto out;
 		}
 	}
+#endif /* CONFIG_MMU */
 
 	error = flock64_to_posix_lock(filp, file_lock, &flock);
 	if (error)
diff -Nru linux-2.5.74-uc0/include/asm-m68knommu/mmu.h linux-2.5.x/include/asm-m68knommu/mmu.h
--- linux-2.5.74-uc0/include/asm-m68knommu/mmu.h	2003-07-02 22:51:46.000000000 +0200
+++ linux-2.5.x/include/asm-m68knommu/mmu.h	2003-07-03 09:37:22.000000000 +0200
@@ -4,9 +4,10 @@
 /* Copyright (C) 2002, David McCullough <davidm@snapgear.com> */
 
 struct mm_rblock_struct {
-	int	size;
-	int	refcount;
-	void	*kblock;
+	int		size;
+	int		refcount;
+	struct file	*file;
+	void		*kblock;
 };
 
 struct mm_tblock_struct {
diff -Nru linux-2.5.74-uc0/include/linux/fs.h linux-2.5.x/include/linux/fs.h
--- linux-2.5.74-uc0/include/linux/fs.h	2003-07-02 22:43:46.000000000 +0200
+++ linux-2.5.x/include/linux/fs.h	2003-07-03 09:37:22.000000000 +0200
@@ -320,9 +320,14 @@
 	struct list_head	io_pages;	/* being prepared for I/O */
 	unsigned long		nrpages;	/* number of total pages */
 	struct address_space_operations *a_ops;	/* methods */
+#ifdef CONFIG_MMU
 	struct list_head	i_mmap;		/* list of private mappings */
 	struct list_head	i_mmap_shared;	/* list of shared mappings */
 	struct semaphore	i_shared_sem;	/* protect both above lists */
+#else /* !CONFIG_MMU */
+	char *			i_mmap_block;	/* Pointer to memory buffer for mmapped file */
+	int			i_mmap_cnt;	/* Track use count of i_mmap_block (FIXME: shall we use atomic_t?) */
+#endif /* !CONFIG_MMU */
 	unsigned long		dirtied_when;	/* jiffies of first page dirtying */
 	int			gfp_mask;	/* how to allocate the pages */
 	struct backing_dev_info *backing_dev_info; /* device readahead, etc */
diff -Nru linux-2.5.74-uc0/mm/filemap.c linux-2.5.x/mm/filemap.c
--- linux-2.5.74-uc0/mm/filemap.c	2003-07-02 22:45:11.000000000 +0200
+++ linux-2.5.x/mm/filemap.c	2003-07-03 09:37:22.000000000 +0200
@@ -40,6 +40,9 @@
 #include <asm/uaccess.h>
 #include <asm/mman.h>
 
+/* Turn on verbose debug messages for mmap related stuff */
+#undef DEBUG_MMAP
+
 /*
  * Shared mappings implemented 30.11.1994. It's not fully working yet,
  * though.
@@ -580,12 +583,14 @@
 		if (!PageUptodate(page))
 			goto page_not_up_to_date;
 page_ok:
+#ifdef CONFIG_MMU
 		/* If users can be writing to this page using arbitrary
 		 * virtual addresses, take care about potential aliasing
 		 * before reading the page on the kernel side.
 		 */
 		if (!list_empty(&mapping->i_mmap_shared))
 			flush_dcache_page(page);
+#endif /* CONFIG_MMU */
 
 		/*
 		 * Mark the page accessed if we read the beginning.
@@ -1262,6 +1267,56 @@
 	return 0;
 }
 
+#else /* !CONFIG_MMU */
+
+int generic_file_mmap(struct file * file, struct vm_area_struct * vma)
+{
+	struct address_space *mapping = file->f_dentry->d_inode->i_mapping;
+	size_t error;
+	mm_segment_t old_fs;
+	size_t len = vma->vm_end - vma->vm_start;
+
+	if (++mapping->i_mmap_cnt == 1)
+	{
+#ifdef DEBUG_MMAP
+		printk("generic_file_mmap(): allocating %u bytes for inode #%ld\n",
+			len, mapping->host->i_ino);
+#endif
+		if (!(mapping->i_mmap_block = kmalloc(len, GFP_KERNEL)))
+		{
+			--mapping->i_mmap_cnt;
+			return -ENOMEM;
+		}
+	}
+#ifdef DEBUG_MMAP
+	else
+		printk("mmap: reusing allocated block for inode #%ld (i_mmap_cnt = %d)\n",
+			mapping->host->i_ino, mapping->i_mmap_cnt);
+#endif
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	error = file->f_op->read(file, mapping->i_mmap_block, len, &file->f_pos);
+	set_fs(old_fs);
+
+	if (error < 0) {
+		if (--mapping->i_mmap_cnt == 0)
+		{
+			kfree(mapping->i_mmap_block);
+			mapping->i_mmap_block = NULL;
+		}
+		return error;
+	}
+
+	/* Clear rest of mapped block */
+	if (error < len)
+		memset(mapping->i_mmap_block + error, 0, len - error);
+
+	vma->vm_start = (unsigned long)mapping->i_mmap_block;
+	return 0;
+}
+#endif /* !CONFIG_MMU */
+
 /*
  * This is for filesystems which do not implement ->writepage.
  */
@@ -1271,16 +1326,6 @@
 		return -EINVAL;
 	return generic_file_mmap(file, vma);
 }
-#else
-int generic_file_mmap(struct file * file, struct vm_area_struct * vma)
-{
-	return -ENOSYS;
-}
-int generic_file_readonly_mmap(struct file * file, struct vm_area_struct * vma)
-{
-	return -ENOSYS;
-}
-#endif /* CONFIG_MMU */
 
 static inline struct page *__read_cache_page(struct address_space *mapping,
 				unsigned long index,
diff -Nru linux-2.5.74-uc0/mm/nommu.c linux-2.5.x/mm/nommu.c
--- linux-2.5.74-uc0/mm/nommu.c	2003-07-03 08:39:17.000000000 +0200
+++ linux-2.5.x/mm/nommu.c	2003-07-03 10:24:12.000000000 +0200
@@ -17,13 +17,18 @@
 #include <linux/pagemap.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
-#include <linux/blkdev.h>
+#include <linux/file.h>
 
 #include <asm/pgalloc.h>
 #include <asm/uaccess.h>
 #include <asm/tlb.h>
 #include <asm/tlbflush.h>
 
+/* Define to enable debug output for mm */
+#undef DEBUG
+#undef DEBUG_TBLOCK
+#undef WARN_ON_SLACK /* 64 */
+
 void *high_memory;
 struct page *mem_map = NULL;
 unsigned long max_mapnr;
@@ -250,9 +255,9 @@
 #undef _trans
 }
 
-#ifdef DEBUG
 static void show_process_blocks(void)
 {
+#ifdef DEBUG_TBLOCK
 	struct mm_tblock_struct *tblock;
 
 	printk("Process blocks %d:", current->pid);
@@ -263,8 +268,110 @@
 			printk(" (%d @%p #%d)", kobjsize(tblock->rblock->kblock), tblock->rblock->kblock, tblock->rblock->refcount);
 		printk(tblock->next ? " ->" : ".\n");
 	}
+#endif /* DEBUG_TBLOCK */
+}
+
+static struct mm_tblock_struct *create_tblock(struct mm_struct *mm, void *kblock, size_t size)
+{
+	struct mm_tblock_struct *tblock;
+
+	if (!(tblock = (struct mm_tblock_struct *)
+		 	kmalloc(sizeof(struct mm_tblock_struct), GFP_KERNEL)))
+		goto out;
+
+	if (!(tblock->rblock = (struct mm_rblock_struct *)
+			kmalloc(sizeof(struct mm_rblock_struct), GFP_KERNEL)))
+		goto out;
+
+	if (!kblock) {
+		if (!(kblock = kmalloc(size, GFP_KERNEL)))
+			goto out;
+
+		memset(kblock, '\0', size);
+
+		realalloc += kobjsize(kblock);
+		askedalloc += size;
+	}
+
+	/* Init rblock */
+	tblock->rblock->refcount = 1;
+	tblock->rblock->file = NULL;
+	tblock->rblock->kblock = kblock;
+	tblock->rblock->size = size;
+
+#ifdef WARN_ON_SLACK
+	if ((size + WARN_ON_SLACK) <= kobjsize(kblock))
+		printk("Allocation of %u bytes from process %d has %u bytes of slack\n",
+			size, current->pid, kobjsize(kblock) - size);
+#endif
+
+	realalloc += kobjsize(tblock);
+	askedalloc += sizeof(struct mm_tblock_struct);
+
+	realalloc += kobjsize(tblock->rblock);
+	askedalloc += sizeof(struct mm_rblock_struct);
+
+	/* Link tblock into mm list */
+	tblock->next = current->mm->context.tblock.next;
+	current->mm->context.tblock.next = tblock;
+
+	return tblock;
+
+out:
+	printk("Allocation of %u bytes failed (pid=%d)\n", size, current->pid);
+	show_free_areas();
+	if (tblock) {
+		kfree(tblock->rblock);
+		kfree(tblock);
+	}
+
+	return NULL;
+}
+
+void delete_tblock(struct mm_tblock_struct *tblock, struct mm_tblock_struct *prev)
+{
+	if (tblock->rblock) {
+		if (!--tblock->rblock->refcount) {
+			struct file *file;
+
+			if ((file = tblock->rblock->file)) {
+				struct address_space *mapping;
+
+				mapping = file->f_dentry->d_inode->i_mapping;
+
+#ifdef DEBUG
+				printk("delete_tblock(): releasing file with f_count %d, i_mmap_cnt %d, (inode #%ld)\n",
+					file->f_count.counter, mapping->i_mmap_cnt, mapping->host->i_ino);
+#endif
+				if (--mapping->i_mmap_cnt == 0) {
+#ifdef DEBUG
+					printk("delete_tblock(): freeing mmapped block @%p (inode #%ld).\n",
+						mapping->i_mmap_block, mapping->host->i_ino);
+#endif
+					kfree(mapping->i_mmap_block);
+					mapping->i_mmap_block = NULL;
+				}
+
+				fput(file);
+			}
+			else if (tblock->rblock->kblock) {
+				realalloc -= kobjsize(tblock->rblock->kblock);
+				askedalloc -= tblock->rblock->size;
+				kfree(tblock->rblock->kblock);
+			}
+
+			realalloc -= kobjsize(tblock->rblock);
+			askedalloc -= sizeof(struct mm_rblock_struct);
+			kfree(tblock->rblock);
+		}
+	}
+
+	/* Unlink tblock from mm list */
+	prev->next = tblock->next;
+	realalloc -= kobjsize(tblock);
+	askedalloc -= sizeof(struct mm_tblock_struct);
+	kfree(tblock);
 }
-#endif /* DEBUG */
 
 unsigned long do_mmap_pgoff(
 	struct file * file,
@@ -274,7 +381,6 @@
 	unsigned long flags,
 	unsigned long pgoff)
 {
-	void * result;
 	struct mm_tblock_struct * tblock;
 	unsigned int vm_flags;
 
@@ -348,95 +454,42 @@
 		   or do something truly complicated. */
 		   
 		if (file->f_op->mmap) {
+			get_file(file);
 			error = file->f_op->mmap(file, &vma);
-				   
 #ifdef DEBUG
 			printk("f_op->mmap() returned %d/%lx\n", error, vma.vm_start);
 #endif
-			if (!error)
-				return vma.vm_start;
-			else if (error != -ENOSYS)
+			if (error)
+			{
+				fput(file);
 				return error;
-		} else
-			return -ENODEV; /* No mapping operations defined */
-
-		/* An ENOSYS error indicates that mmap isn't possible (as opposed to
-		   tried but failed) so we'll fall through to the copy. */
-	}
-
-	tblock = (struct mm_tblock_struct *)
-                        kmalloc(sizeof(struct mm_tblock_struct), GFP_KERNEL);
-	if (!tblock) {
-		printk("Allocation of tblock for %lu byte allocation from process %d failed\n", len, current->pid);
-		show_free_areas();
-		return -ENOMEM;
-	}
+			}
 
-	tblock->rblock = (struct mm_rblock_struct *)
-			kmalloc(sizeof(struct mm_rblock_struct), GFP_KERNEL);
+			if (!(tblock = create_tblock(current->mm, (void *)vma.vm_start, vma.vm_end - vma.vm_start)))
+			{
+				fput(file);
+				return -ENOMEM;
+			}
 
-	if (!tblock->rblock) {
-		printk("Allocation of rblock for %lu byte allocation from process %d failed\n", len, current->pid);
-		show_free_areas();
-		kfree(tblock);
-		return -ENOMEM;
-	}
+			tblock->rblock->file = file;
 
-	result = kmalloc(len, GFP_KERNEL);
-	if (!result) {
-		printk("Allocation of length %lu from process %d failed\n", len,
-				current->pid);
-		show_free_areas();
-		kfree(tblock->rblock);
-		kfree(tblock);
-		return -ENOMEM;
+		} else
+			return -ENODEV; /* No mapping operations defined */
 	}
-
-	tblock->rblock->refcount = 1;
-	tblock->rblock->kblock = result;
-	tblock->rblock->size = len;
-	
-	realalloc += kobjsize(result);
-	askedalloc += len;
-
-#ifdef WARN_ON_SLACK	
-	if ((len+WARN_ON_SLACK) <= kobjsize(result))
-		printk("Allocation of %lu bytes from process %d has %lu bytes of slack\n", len, current->pid, kobjsize(result)-len);
-#endif
-	
-	if (file) {
-		int error;
-		mm_segment_t old_fs = get_fs();
-		set_fs(KERNEL_DS);
-		error = file->f_op->read(file, (char *) result, len, &file->f_pos);
-		set_fs(old_fs);
-		if (error < 0) {
-			kfree(result);
-			kfree(tblock->rblock);
-			kfree(tblock);
-			return error;
-		}
-		if (error < len)
-			memset(result+error, '\0', len-error);
-	} else {
-		memset(result, '\0', len);
+	else
+	{
+		/* Handle anonymous mapping */
+		if (!(tblock = create_tblock(current->mm, NULL, len)))
+			return -ENOMEM;
 	}
 
-	realalloc += kobjsize(tblock);
-	askedalloc += sizeof(struct mm_tblock_struct);
-
-	realalloc += kobjsize(tblock->rblock);
-	askedalloc += sizeof(struct mm_rblock_struct);
-
-	tblock->next = current->mm->context.tblock.next;
-	current->mm->context.tblock.next = tblock;
-
 #ifdef DEBUG
 	printk("do_mmap:\n");
 	show_process_blocks();
-#endif	  
+#endif
 
-	return (unsigned long)result;
+	/* Return addr of mmapped memory block */
+	return (unsigned long) tblock->rblock->kblock;
 }
 
 int do_munmap(struct mm_struct * mm, unsigned long addr, size_t len)
@@ -466,27 +519,9 @@
 				current->pid, current->comm, (void*)addr);
 		return -EINVAL;
 	}
-	if (tblock->rblock) {
-		if (!--tblock->rblock->refcount) {
-			if (tblock->rblock->kblock) {
-				realalloc -= kobjsize(tblock->rblock->kblock);
-				askedalloc -= tblock->rblock->size;
-				kfree(tblock->rblock->kblock);
-			}
-			
-			realalloc -= kobjsize(tblock->rblock);
-			askedalloc -= sizeof(struct mm_rblock_struct);
-			kfree(tblock->rblock);
-		}
-	}
-	tmp->next = tblock->next;
-	realalloc -= kobjsize(tblock);
-	askedalloc -= sizeof(struct mm_tblock_struct);
-	kfree(tblock);
 
-#ifdef DEBUG
+	delete_tblock(tblock, tmp);
 	show_process_blocks();
-#endif	  
 
 	return -EINVAL;
 }
@@ -504,28 +539,8 @@
 #endif
 
 	while((tmp = mm->context.tblock.next)) {
-		if (tmp->rblock) {
-			if (!--tmp->rblock->refcount) {
-				if (tmp->rblock->kblock) {
-					realalloc -= kobjsize(tmp->rblock->kblock);
-					askedalloc -= tmp->rblock->size;
-					kfree(tmp->rblock->kblock);
-				}
-				realalloc -= kobjsize(tmp->rblock);
-				askedalloc -= sizeof(struct mm_rblock_struct);
-				kfree(tmp->rblock);
-			}
-			tmp->rblock = 0;
-		}
-		mm->context.tblock.next = tmp->next;
-		realalloc -= kobjsize(tmp);
-		askedalloc -= sizeof(struct mm_tblock_struct);
-		kfree(tmp);
+		delete_tblock(mm->context.tblock.next, &mm->context.tblock);
 	}
-
-#ifdef DEBUG
-	show_process_blocks();
-#endif	  
 }
 
 asmlinkage long sys_munmap(unsigned long addr, size_t len)
diff -Nru linux-2.5.74-uc0/mm/vmscan.c linux-2.5.x/mm/vmscan.c
--- linux-2.5.74-uc0/mm/vmscan.c	2003-07-02 22:41:46.000000000 +0200
+++ linux-2.5.x/mm/vmscan.c	2003-07-03 09:37:22.000000000 +0200
@@ -189,11 +189,13 @@
 	if (PageSwapCache(page))
 		return 1;
 
+#ifdef CONFIG_MMU
 	/* File is mmap'd by somebody. */
 	if (!list_empty(&mapping->i_mmap))
 		return 1;
 	if (!list_empty(&mapping->i_mmap_shared))
 		return 1;
+#endif /* CONFIG_MMU */
 
 	return 0;
 }
