diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c
index 5b06f92..85e1cb0 100644
--- a/drivers/usb/storage/initializers.c
+++ b/drivers/usb/storage/initializers.c
@@ -45,6 +45,12 @@
 #include "debug.h"
 #include "transport.h"
 
+#define RIO_MSC 0x08
+#define RIOP_INIT "RIOP\x00\x01\x08"
+#define RIOP_INIT_LEN 7
+#define RIO_SEND_LEN 40
+#define RIO_RECV_LEN 0x200
+
 /* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target
  * mode */
 int usb_stor_euscsi_init(struct us_data *us)
@@ -91,3 +97,70 @@ int usb_stor_ucr61s2b_init(struct us_dat
 
 	return (res ? -1 : 0);
 }
+
+/* Place the Rio Karma into mass storage mode.
+ * 
+ * The initialization begins by sending 40 bytes starting
+ * RIOP\x00\x01\x08\x00, which the device will ack with a 512-byte
+ * packet with the high four bits set and everything else null.
+ *
+ * Next, we send RIOP\x80\x00\x08\x00.  Each time, a 512 byte response
+ * must be read, but we must loop until byte 5 in the response is 0x08,
+ * indicating success.  */
+int rio_karma_init(struct us_data *us) 
+{
+	int result, partial;
+	char *recv;
+	unsigned long timeout;
+
+	memset(us->iobuf, 0, RIO_SEND_LEN);
+	memcpy(us->iobuf, RIOP_INIT, RIOP_INIT_LEN);
+
+	// us->iobuf is big enough to hold cmd but not receive
+	if (!(recv = kmalloc(RIO_RECV_LEN, GFP_KERNEL)))
+		goto die_nomem;
+
+	US_DEBUGP("Initializing Karma...\n");
+
+	result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, 
+		us->iobuf, RIO_SEND_LEN, &partial);
+	if (result != USB_STOR_XFER_GOOD)
+		goto die;
+
+	result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, 
+		recv, RIO_RECV_LEN, &partial);
+	if (result != USB_STOR_XFER_GOOD)
+		goto die;
+
+	us->iobuf[4] = 0x80;
+	us->iobuf[5] = 0;
+	timeout = jiffies + msecs_to_jiffies(3000); 
+	for (;;) {
+		US_DEBUGP("Sending init command\n");
+		result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, 
+			us->iobuf, RIO_SEND_LEN, &partial);
+		if (result != USB_STOR_XFER_GOOD)
+			goto die;
+
+		result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, 
+			recv, RIO_RECV_LEN, &partial);
+		if (result != USB_STOR_XFER_GOOD)
+			goto die;
+		
+		if (recv[5] == RIO_MSC) 
+			break;
+		if (time_after(jiffies, timeout))
+			goto die;
+		msleep(10);
+	}
+	US_DEBUGP("Karma initialized.\n");
+	kfree(recv);
+	return 0;
+
+die:
+	kfree(recv);
+die_nomem:
+	US_DEBUGP("Could not initialize karma.\n");
+	return USB_STOR_TRANSPORT_FAILED;
+}
+
diff --git a/drivers/usb/storage/initializers.h b/drivers/usb/storage/initializers.h
index 7372386..fa9a2ff 100644
--- a/drivers/usb/storage/initializers.h
+++ b/drivers/usb/storage/initializers.h
@@ -52,3 +52,4 @@ int sddr09_init(struct us_data *us);
 /* This function is required to activate all four slots on the UCR-61S2B
  * flash reader */
 int usb_stor_ucr61s2b_init(struct us_data *us);
+int rio_karma_init(struct us_data *us);
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 0a9858f..0cdfebf 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -145,6 +145,11 @@ UNUSUAL_DEV(  0x0451, 0x5416, 0x0100, 0x
 		US_SC_DEVICE, US_PR_BULK, NULL,
 		US_FL_NEED_OVERRIDE ),
 
+UNUSUAL_DEV(  0x045a, 0x5210, 0x0101, 0x0101,
+		"Rio",
+		"Rio Karma",
+		US_SC_SCSI, US_PR_BULK, rio_karma_init, 0),
+
 /* Patch submitted by Philipp Friedrich <philipp@void.at> */
 UNUSUAL_DEV(  0x0482, 0x0100, 0x0100, 0x0100,
 		"Kyocera",
diff --git a/fs/Kconfig b/fs/Kconfig
index d5255e6..87ac8fd 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1248,6 +1248,10 @@ config SYSV_FS
 	  If you haven't heard about all of this before, it's safe to say N.
 
 
+config OMFS_FS
+	tristate "OMFS (Rio Karma)"
+	help
+	  Say 'Y' to get support for the RIO Karma fs.
 
 config UFS_FS
 	tristate "UFS file system support (read only)"
diff --git a/fs/Makefile b/fs/Makefile
index 4c26557..9efa233 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -100,4 +100,5 @@ obj-$(CONFIG_AFS_FS)		+= afs/
 obj-$(CONFIG_BEFS_FS)		+= befs/
 obj-$(CONFIG_HOSTFS)		+= hostfs/
 obj-$(CONFIG_HPPFS)		+= hppfs/
+obj-$(CONFIG_OMFS_FS)		+= omfs/
 obj-$(CONFIG_DEBUG_FS)		+= debugfs/
diff --git a/fs/omfs/Makefile b/fs/omfs/Makefile
new file mode 100644
index 0000000..667e918
--- /dev/null
+++ b/fs/omfs/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for OMFS filesystem.
+#
+
+
+obj-$(CONFIG_OMFS_FS) += omfs.o
+
+omfs-objs := inode.o dir.o file.o bitmap.o checksum.o
diff --git a/fs/omfs/bitmap.c b/fs/omfs/bitmap.c
new file mode 100644
index 0000000..cb8e5ad
--- /dev/null
+++ b/fs/omfs/bitmap.c
@@ -0,0 +1,22 @@
+#include "omfs.h"
+
+static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
+
+unsigned long omfs_count_free(struct super_block *sb)
+{
+	unsigned int i, j, count = 0;
+	long *map;
+	unsigned long sum = 0;
+	struct omfs_sb_info *sbi = OMFS_SB(sb);
+	
+	for (i = 0; i < sbi->imap_size; i++)
+	{
+		map = sbi->imap[i];
+		for (j=0; j < sb->s_blocksize && 
+				count + j < sbi->num_blocks; j++)
+			sum += nibblemap[map[j] & 0xf] +
+				nibblemap[(map[j] >> 4) & 0xf];
+		count += sb->s_blocksize;
+	}
+	return (sum);
+}
diff --git a/fs/omfs/checksum.c b/fs/omfs/checksum.c
new file mode 100644
index 0000000..481278c
--- /dev/null
+++ b/fs/omfs/checksum.c
@@ -0,0 +1,70 @@
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/buffer_head.h>
+#include "omfs.h"
+
+#define POLY 0x1021
+
+/*
+ * crc-ccitt with MSB first (i.e., backwards), so we can't use the
+ * kernel table as-is.  
+ */
+static u16 omfs_crc(u16 crc, unsigned char *buf, int count)
+{
+	int i, j;
+	printk(KERN_DEBUG "omfs: in crc for count %x\n", crc);
+	for (i=0; i<count; i++) {
+		crc ^= buf[i] << 8;
+		for (j = 0; j < 8; j++)
+			crc = (crc << 1) ^ ((crc & 0x8000) ? POLY : 0);
+	}
+	return crc;
+}
+
+/*
+ * Update the header checksums for a dirty inode based on its contents.
+ * Caller is expected to hold the buffer head underlying oi and mark it 
+ * dirty.
+ */
+int omfs_update_checksums(struct omfs_inode *oi, struct inode *inode)
+{
+#ifdef OMFS_WRITE
+	int xor, i, ofs=0, ret=0, count;
+	struct super_block *sb = inode->i_sb;
+	int block = clus_to_blk(inode->i_ino);
+	u16 crc=0;
+	struct buffer_head *bh;
+	unsigned char *ptr = (unsigned char *) oi;
+
+	count = be32_to_cpu(oi->head.body_size);
+	ofs = sizeof(struct omfs_header);
+
+	printk(KERN_DEBUG "omfs: body size is %x\n", count);
+
+	for (; count > 0; count -= sb->s_blocksize) {
+		bh = sb_bread(inode->i_sb, block++);
+		if (!bh) {
+			ret = -ENOMEM;
+			goto out;
+		}
+		// count will always fall on a blocksize boundary
+		crc = omfs_crc(crc, &bh->b_data[ofs], sb->s_blocksize - ofs);
+		brelse(bh);
+		ofs = 0;
+	}
+
+	oi->head.crc = cpu_to_be16(crc);
+
+	xor = ptr[0];
+	for (i=1; i<OMFS_XOR_COUNT; i++)
+		xor ^= ptr[i];
+
+	oi->head.check_xor = xor;
+out:
+	printk(KERN_DEBUG "Calculated checksum for %lx as %x\n", 
+		inode->i_ino, crc);
+	return ret;
+#endif
+}
+
+
diff --git a/fs/omfs/dir.c b/fs/omfs/dir.c
new file mode 100644
index 0000000..37d4f3e
--- /dev/null
+++ b/fs/omfs/dir.c
@@ -0,0 +1,327 @@
+/*
+ * fs/omfs/dir.c
+ * OMFS (as used by RIO Karma) directory operations.
+ * Copyright (C) 2005 Bob Copeland <me@bobcopeland.com>
+ */
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/ctype.h>
+#include <linux/buffer_head.h>
+#include "omfs.h"
+
+static int omfs_hash(const char *name, int namelen, int mod)
+{
+	int i, hash=0;
+	for (i=0; i<namelen; i++)
+		hash ^= tolower(name[i]) << (i % 24);
+	return hash % mod;
+}
+
+/* 
+ * Finds the bucket for a given name and reads the containing block; 
+ * *ofs is set to the offset of the first list entry.
+ */
+static struct buffer_head *omfs_get_bucket(struct inode *dir, 
+		const char *name, int namelen, int *ofs)
+{
+	loff_t ptr;
+	int nbuckets = (dir->i_size - OMFS_DIR_START)/8;
+	int block = clus_to_blk(dir->i_ino);
+	int bucket = omfs_hash(name, namelen, nbuckets);
+
+	ptr = OMFS_DIR_START + bucket * 8;
+	block += ptr >> dir->i_sb->s_blocksize_bits;
+	*ofs = ptr & (dir->i_sb->s_blocksize - 1);
+
+	return sb_bread(dir->i_sb, block);
+}
+
+static struct buffer_head *omfs_find_entry(struct inode *dir,
+					   const char *name, int namelen)
+{
+	struct buffer_head *bh;
+	struct omfs_inode *oi;
+	int ofs;
+	u64 cluster;
+	bh = omfs_get_bucket(dir, name, namelen, &ofs);
+	if (!bh)
+		goto out;
+
+	cluster = be64_to_cpu(*((u64 *) & bh->b_data[ofs]));
+	brelse(bh);
+	while (cluster != ~0) {
+		bh = sb_bread(dir->i_sb, clus_to_blk(cluster));
+		if (!bh)
+			goto out;
+
+		oi = (struct omfs_inode *)bh->b_data;
+		if (strncmp(oi->name, name, namelen) == 0) {
+			return bh;
+		}
+		cluster = be64_to_cpu(oi->sibling);
+		brelse(bh);
+	}
+out:
+	return NULL;
+}
+
+#ifdef OMFS_WRITE
+int omfs_make_empty(struct inode *inode, struct super_block *sb)
+{
+	int i;
+	int block = clus_to_blk(inode->i_ino);
+	int first = 1;
+	struct buffer_head *bh;
+
+	for (i=0; i < OMFS_SB(sb)->sys_blocksize; i += sb->s_blocksize)
+	{
+		bh = sb_bread(sb, block++);
+		if (!bh)
+			return -ENOMEM;
+
+		if (first) {
+			memset(bh->b_data, 0, OMFS_DIR_START);
+			memset(&bh->b_data[OMFS_DIR_START], 0xff, 
+				sb->s_blocksize - OMFS_DIR_START);
+		} else
+			memset(bh->b_data, 0xff, sb->s_blocksize);
+		mark_buffer_dirty(bh);
+		brelse(bh);
+		first = 0;
+	}
+	return 0;
+}
+
+int omfs_add_link(struct dentry *dentry, struct inode *inode)
+{
+	struct inode *dir = dentry->d_parent->d_inode;
+	const char *name = dentry->d_name.name;
+	int namelen = dentry->d_name.len;
+	struct omfs_inode *oi;
+	struct buffer_head *bh;
+	u64 cluster;
+	u64 *entry;
+	int ofs;
+
+	// just prepend to head of queue in proper bucket and we are done. 
+	bh = omfs_get_bucket(dir, name, namelen, &ofs);
+	if (!bh)
+		goto out;
+
+	entry = (u64 *) &bh->b_data[ofs];
+	cluster = be64_to_cpu(*entry);
+	*entry = cpu_to_be64(inode->i_ino);
+	mark_buffer_dirty(bh);
+	brelse(bh); 
+
+	// now set the sibling and parent pointers on the new inode
+	bh = sb_bread(dir->i_sb, clus_to_blk(inode->i_ino));
+	if (!bh)
+		goto out;
+
+	oi = (struct omfs_inode *) bh->b_data;
+	memcpy (oi->name, name, namelen);
+	memset (oi->name + namelen, 0, OMFS_NAMELEN - namelen);
+	oi->sibling = cpu_to_be64(cluster);
+	oi->parent = cpu_to_be64(dir->i_ino);
+	mark_buffer_dirty(bh);
+	brelse(bh);
+
+	dir->i_ctime = CURRENT_TIME_SEC;
+
+	// mark affected inodes dirty to rebuild checksums
+	mark_inode_dirty(dir);
+	mark_inode_dirty(inode);
+	return 0;
+out:
+	return -ENOMEM;
+}
+
+static int omfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+	int err = 0;
+	struct inode *inode;
+
+	mode |= S_IFDIR;
+
+	inode = omfs_new_inode(dir, mode);
+	if (!inode)
+		return -ENOSPC;
+
+	if (dir->i_mode & S_ISGID) {
+		inode->i_gid = dir->i_gid;
+		if (S_ISDIR(mode))
+			inode->i_mode |= S_ISGID;
+	}
+
+	printk(KERN_DEBUG "I just made an inode at block %lx\n", inode->i_ino);
+
+	err = omfs_make_empty(inode, dir->i_sb);
+	if (err)
+		goto out;
+
+	err = omfs_add_link(dentry, inode); 
+	if (err)
+		goto out;
+
+	d_instantiate(dentry, inode);
+out:
+	return err;
+}
+
+// TODO: omfs_make_empty can handle both dirs and files; then
+// omfs_mkdir and omfs_create are the same (use mknod?)
+
+static int omfs_create(struct inode * dir, struct dentry * dentry, int mode,
+		struct nameidata *nd)
+{
+	int err;
+	struct inode * inode;
+
+	mode |= S_IFREG;
+
+	inode = omfs_new_inode(dir, mode);
+	if (!inode)
+		return -ENOSPC;
+
+	err = omfs_make_empty_file(inode, dir->i_sb);
+	if (err)
+		goto out;
+
+	err = omfs_add_link(dentry, inode); 
+	if (err)
+		goto out;
+	
+	d_instantiate(dentry, inode);
+out:
+	return err;
+}
+#endif
+
+static struct dentry *omfs_lookup(struct inode *dir, struct dentry *dentry,
+				  struct nameidata *nd)
+{
+	struct buffer_head *bh;
+	struct inode *inode = NULL;
+
+	if (dentry->d_name.len > OMFS_NAMELEN)
+		return ERR_PTR(-ENAMETOOLONG);
+
+	bh = omfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len);
+	if (bh) {
+		struct omfs_inode *oi = (struct omfs_inode *)bh->b_data;
+		ino_t ino = be64_to_cpu(oi->head.self);
+		brelse(bh);
+		inode = iget(dir->i_sb, ino);
+		if (!inode) {
+			return ERR_PTR(-EINVAL);	
+		}
+	}
+	d_add(dentry, inode);
+	return NULL;
+}
+
+static int omfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+	struct inode *dir = filp->f_dentry->d_inode;
+	struct buffer_head *bh = NULL, *bh2;
+	struct omfs_inode *oi;
+	loff_t bl_ofs;
+	loff_t offset, res;
+	u64 cluster;
+	unsigned char d_type;
+	ino_t self;
+	unsigned int hchain, hindex;
+	sector_t block;
+	int nbuckets;
+
+	printk(KERN_DEBUG "Reading inode %lx\n", dir->i_ino);
+
+	switch (filp->f_pos) {
+	case 0:
+		if (filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR) < 0) 
+			goto success;
+		filp->f_pos++;
+		/* fall through */
+	case 1:
+		if (filldir(dirent, "..", 2, 1, parent_ino(filp->f_dentry), DT_DIR) < 0) 
+			goto success;
+		filp->f_pos = 0x01000000;
+		/* fall through */
+	}
+
+	nbuckets = (dir->i_size - OMFS_DIR_START) / 8;
+
+	/* high byte stores bucket + 1 and low 24 bits store hash index */
+	hchain = (filp->f_pos >> 24) -1;
+	hindex = filp->f_pos & 0xffffff;
+
+	for (; hchain < nbuckets; hchain++) {
+		offset = OMFS_DIR_START + hchain * 8;
+
+		bl_ofs = offset & (dir->i_sb->s_blocksize - 1);
+		if (!bl_ofs || !bh) { // wrapped a block
+			brelse(bh);
+			block = offset >> dir->i_sb->s_blocksize_bits;
+			bh = sb_bread(dir->i_sb, block + 
+					clus_to_blk(dir->i_ino));
+			if (!bh) 
+				goto no_bh;
+		}
+		cluster = be64_to_cpu(*((u64 *) & bh->b_data[bl_ofs]));
+		while (cluster != ~0) {
+			bh2 = sb_bread(dir->i_sb, clus_to_blk(cluster));
+			if (!bh2)
+				goto no_bh2;
+
+			oi = (struct omfs_inode *)bh2->b_data;
+			self = cluster;
+			cluster = be64_to_cpu(oi->sibling);
+
+			if (hindex) { 
+				hindex--;
+				brelse(bh2);
+				continue;
+			}
+
+			if (oi->type == OMFS_DIR)
+				d_type = DT_DIR;
+			else
+				d_type = DT_REG;
+
+			res = filldir(dirent, oi->name, strnlen(oi->name, 
+				OMFS_NAMELEN), filp->f_pos, self, d_type);
+			brelse(bh2);
+			if (res < 0) 
+			{
+				brelse(bh);
+				goto success;
+			}
+			filp->f_pos++;
+		}
+		filp->f_pos = (hchain+2) << 24;
+	}
+	brelse(bh);
+
+success:
+	return 0;
+no_bh2:
+	brelse(bh);
+no_bh:
+	return -EINVAL;
+}
+
+struct inode_operations omfs_dir_inops = {
+	.lookup = omfs_lookup,
+#ifdef OMFS_WRITE
+	.mkdir = omfs_mkdir,
+	.rename = simple_rename,
+	.create = omfs_create,
+#endif
+};
+
+struct file_operations omfs_dir_operations = {
+	.read = generic_read_dir,
+	.readdir = omfs_readdir,
+};
diff --git a/fs/omfs/file.c b/fs/omfs/file.c
new file mode 100644
index 0000000..972792a
--- /dev/null
+++ b/fs/omfs/file.c
@@ -0,0 +1,202 @@
+/*
+ * fs/omfs/file.c
+ * OMFS (as used by RIO Karma) file operations.
+ * Copyright (C) 2005 Bob Copeland <me@bobcopeland.com>
+ */
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/buffer_head.h>
+#include "omfs.h"
+
+int omfs_make_empty_file(struct inode *inode, struct super_block *sb)
+{
+	int block = clus_to_blk(inode->i_ino);
+	struct buffer_head *bh;
+
+	struct omfs_extent oe = {
+		.next = ~0,
+		.extent_count = 0,
+		.fill = cpu_to_be32(0x22), /* FIXME ? */
+	};
+
+	bh = sb_bread(sb, block++);
+	if (!bh)
+		return -ENOMEM;
+
+	memset(bh->b_data, 0, OMFS_EXTENT_START);
+	memcpy(&bh->b_data[OMFS_EXTENT_START], &oe, sizeof(struct omfs_extent));
+	mark_buffer_dirty(bh);
+	brelse(bh);
+
+	return 0;
+}
+
+/* 
+ * Scans across the directory table for a given block number.  There are 
+ * several possible exit conditions: 
+ * 1) we find the cluster and return it
+ * 2) count is zero (for this table); we return 0 and *count is zero.
+ * 3) no more pointers on this page (but more in table); return 0 and
+ * *count is non-zero.  caller must repeat with ent on next block.
+ */
+static sector_t find_block(struct inode *inode, struct omfs_extent_entry *ent, 
+	 	       sector_t block, sector_t *searched,
+		       int block_ofs, int *count)
+{
+	for (; *count > 0 && block_ofs < inode->i_sb->s_blocksize; 
+		(*count)--, block_ofs += sizeof(struct omfs_extent_entry))
+	{
+		int numblocks = clus_to_blk(be64_to_cpu(ent->blocks));
+		if (block >= *searched  && 
+		    block < (*searched + numblocks))
+		{
+			// found it at cluster + (block - searched)
+			return clus_to_blk(be64_to_cpu(ent->cluster)) + 
+				block - *searched;
+		}
+		*searched += numblocks;
+		ent++;
+	}
+	return 0;
+}
+
+static int omfs_get_block(struct inode *inode, sector_t block,
+			  struct buffer_head *bh_result, int create)
+{
+	struct buffer_head *bh;
+	sector_t next, block_start, offset, searched=0, new_cluster;
+	int block_ofs, extent_count;
+	struct omfs_extent *oe;
+	struct omfs_extent_entry *entry;
+
+	block_start = clus_to_blk(inode->i_ino);
+	bh = sb_bread(inode->i_sb, block_start);
+	if (!bh)
+		goto err;
+
+	oe = (struct omfs_extent *)(&bh->b_data[OMFS_EXTENT_START]);
+
+	for(;;) {
+		int count;
+
+		extent_count = be32_to_cpu(oe->extent_count);
+		next = be64_to_cpu(oe->next);
+		entry = &oe->entry;
+		block_ofs = (long) entry - (long)bh->b_data;
+
+		count = extent_count;
+		while (count > 0) {
+			offset = find_block(inode, entry, block, &searched, 
+					block_ofs, &count);
+			if (offset > 0) {
+				brelse(bh);
+				map_bh(bh_result, inode->i_sb, offset);
+				return 0;
+			}
+			if (count) {
+				// spilled over a buffer
+				brelse(bh);
+				bh = sb_bread(inode->i_sb, ++block_start);
+				if (!bh) goto err;
+				entry = (struct omfs_extent_entry *) bh->b_data;
+				block_ofs = 0;
+			}
+		}
+		if (next == ~0)
+			break;
+
+		brelse(bh);
+		bh = sb_bread(inode->i_sb, clus_to_blk(next));
+		if (!bh) goto err;
+		oe = (struct omfs_extent *) (&bh->b_data[OMFS_EXTENT_CONT]);
+	}
+	if (!create) {
+		brelse(bh);
+		return 0;
+	}
+
+	/* reached the end of the extent table with no blocks mapped.
+	 * there are three possibilities for adding: grow last extent,
+	 * add a new extent to the current extent table, and add a 
+	 * continuation inode.  in last two cases need an allocator for
+	 * sbi->cluster_size
+	 */
+
+	/* trivially grow current extent, if next block is not taken */
+	block_ofs = (long) entry - (long)bh->b_data;
+	if (extent_count > 1 && block_ofs != 0)
+	{
+		entry -= sizeof(struct omfs_extent_entry);
+
+		new_cluster = be64_to_cpu(entry->cluster) + 
+			be64_to_cpu(entry->blocks) + 1;
+	
+	    	if (omfs_reserve_block(inode->i_sb, new_cluster))
+		{
+			entry->blocks = 
+				cpu_to_be64(be64_to_cpu(entry->blocks) + 1);
+			mark_buffer_dirty(bh);
+			brelse(bh);
+
+			printk(KERN_DEBUG 
+				"omfs: extended %lx to: %llx %llx (%lx)\n", 
+				inode->i_ino, be64_to_cpu(entry->cluster), 
+				be64_to_cpu(entry->blocks), new_cluster);
+
+			map_bh(bh_result, inode->i_sb, 
+				clus_to_blk(new_cluster));
+			return 0;
+		}
+	}
+
+	// add a new extent
+	// if (oe->count * sizeof(entry) + offset > something)
+	//     add a continuation inode
+
+	// oe points to nothing!
+err:
+	return -EIO;
+}
+
+static int omfs_readpage(struct file *file, struct page *page)
+{
+	return block_read_full_page(page, omfs_get_block);
+}
+
+#ifdef OMFS_WRITE
+static int omfs_writepage(struct page *page, struct writeback_control *wbc)
+{
+	return block_write_full_page(page, omfs_get_block, wbc);
+}
+
+static int omfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
+{
+	return block_prepare_write(page,from,to,omfs_get_block);
+}
+
+static sector_t omfs_bmap(struct address_space *mapping, sector_t block)
+{
+	return generic_block_bmap(mapping,block,omfs_get_block);
+}
+#endif
+
+struct file_operations omfs_file_operations = {
+	.llseek = generic_file_llseek,
+	.read = generic_file_read,
+	.write = generic_file_write,
+	.mmap = generic_file_mmap,
+	.sendfile = generic_file_sendfile,
+};
+
+struct address_space_operations omfs_aops = {
+	.readpage = omfs_readpage,
+#ifdef OMFS_WRITE
+	.writepage = omfs_writepage,
+	.sync_page = block_sync_page,
+	.prepare_write = omfs_prepare_write,
+	.commit_write = generic_commit_write,
+	.bmap = omfs_bmap,
+#endif
+};
+
diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c
new file mode 100644
index 0000000..68d1476
--- /dev/null
+++ b/fs/omfs/inode.c
@@ -0,0 +1,504 @@
+/*
+ * Optimized MPEG FS - inode and super operations.
+ * Copyright (C) 2005 Bob Copeland <me@bobcopeland.com>
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/vfs.h>
+#include <linux/buffer_head.h>
+#include <linux/vmalloc.h>
+#include "omfs.h"
+
+MODULE_AUTHOR("Bob Copeland <me@bobcopeland.com>");
+MODULE_DESCRIPTION("OMFS (ReplayTV/Karma) Filesystem for Linux");
+MODULE_LICENSE("GPL");
+
+#ifdef OMFS_WRITE
+
+int omfs_reserve_block(struct super_block *sb, sector_t block)
+{
+	struct buffer_head *bh;
+	struct omfs_sb_info *sbi = OMFS_SB(sb);
+	int bits_per_entry = 8 * sb->s_blocksize;
+	int map = block / bits_per_entry;
+	int bit = block % bits_per_entry;
+
+	if (!test_and_set_bit(bit, sbi->imap[map]))
+		return 0;
+
+	if (sbi->bitmap_ino > 0)
+	{
+		bh = sb_bread(sb, clus_to_blk(sbi->bitmap_ino + map));
+		set_bit(bit, (long*) bh->b_data);
+		mark_buffer_dirty(bh);
+		brelse(bh);
+	}
+	return 1;
+}
+
+static void omfs_set_bit(struct super_block *sb, int block, int bit)
+{
+	struct buffer_head *bh;
+	struct omfs_sb_info *sbi = OMFS_SB(sb);
+
+	set_bit(bit, sbi->imap[block]);
+	if (sbi->bitmap_ino > 0)
+	{
+		bh = sb_bread(sb, clus_to_blk(sbi->bitmap_ino + block));
+		set_bit(bit, (long*) bh->b_data);
+		mark_buffer_dirty(bh);
+		brelse(bh);
+	}
+}
+
+static int find_empty_block(struct super_block *sb, int mode, ino_t *ino)
+{
+	int bit=0, i;
+	struct omfs_sb_info *sbi = OMFS_SB(sb);
+	int block_request = 1;
+	int bits_per_entry = 8 * sb->s_blocksize;
+
+	if (S_ISREG(mode))
+		block_request = sbi->clustersize;
+
+	for (i=0; i < sbi->imap_size; i++)
+	{
+		bit = find_first_zero_bit(sbi->imap[i], bits_per_entry);
+		if (bit < bits_per_entry)
+			break;
+	}
+	*ino = i * bits_per_entry + bit;
+	if (*ino >= sbi->num_blocks)
+		return -ENOSPC;
+	omfs_set_bit(sb, i, bit);
+	return 0;
+}
+#endif
+
+static kmem_cache_t *omfs_inode_cachep;
+
+static struct inode *omfs_alloc_inode(struct super_block *sb)
+{
+	struct omfs_inode_info *oinf;
+	oinf = (struct omfs_inode_info *) kmem_cache_alloc(omfs_inode_cachep, 
+			SLAB_KERNEL);
+	if (!oinf)
+		return NULL;
+	return &oinf->vfs_inode;
+}
+
+static void omfs_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(omfs_inode_cachep, OMFS_I(inode));
+}
+
+static void init_once(void *p, kmem_cache_t *cachep, unsigned long flags)
+{
+	struct omfs_inode_info *oinf = (struct omfs_inode_info *) p;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once(&oinf->vfs_inode);
+}
+ 
+static int init_inodecache(void)
+{
+	omfs_inode_cachep = kmem_cache_create("omfs_inode_cache",
+					     sizeof(struct omfs_inode_info),
+					     0, SLAB_RECLAIM_ACCOUNT,
+					     init_once, NULL);
+	if (!omfs_inode_cachep)
+		return -ENOMEM;
+	return 0;
+}
+
+static void destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(omfs_inode_cachep))
+		printk(KERN_INFO "omfs_inode_cache: not all structures were freed\n");
+}
+
+#ifdef OMFS_WRITE
+struct inode *omfs_new_inode(struct inode *dir, int mode)
+{
+	struct inode *inode;
+	ino_t ino;
+	int res;
+	
+	inode = new_inode(dir->i_sb);
+	if (!inode)
+		return ERR_PTR(-ENOMEM);
+
+	res = find_empty_block(dir->i_sb, mode, &ino);
+	if (res)
+		return ERR_PTR(res);
+
+	inode->i_ino = ino;
+	inode->i_mode = mode;
+	inode->i_uid = current->fsuid;
+	inode->i_gid = current->fsgid;
+	inode->i_blksize = PAGE_SIZE;
+	inode->i_blocks = 0;
+	inode->i_mapping->a_ops = &omfs_aops;
+
+	OMFS_I(inode)->state = OMFS_STATE_NEW;
+
+	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	switch (mode & S_IFMT) {
+	case S_IFDIR:
+		inode->i_op = &omfs_dir_inops;
+		inode->i_fop = &omfs_dir_operations;
+		inode->i_size = OMFS_SB(inode->i_sb)->sys_blocksize;
+		inode->i_nlink++;  /* "." entry */
+		break;
+	case S_IFREG:
+		inode->i_fop = &omfs_file_operations;
+		inode->i_size = 0;
+		break;
+	}
+
+	insert_inode_hash(inode);
+	printk(KERN_DEBUG "omfs: new marked dirty: %lx\n", inode->i_ino);
+	mark_inode_dirty(inode);
+	return inode;
+}
+
+static int omfs_write_inode(struct inode *inode, int wait)
+{
+	struct omfs_inode *oi;
+	struct omfs_sb_info *sbi;
+	struct buffer_head *bh, *bh2;
+	unsigned int block;
+	u64 ctime;
+	int i;
+
+	printk(KERN_DEBUG "omfs: writing inode %lx\n", inode->i_ino);
+
+	sbi = OMFS_SB(inode->i_sb);
+
+	/* get current inode since we may have written sibling ptrs etc. */
+	block = clus_to_blk(inode->i_ino);
+	bh = sb_bread(inode->i_sb, block);
+	if (!bh) 
+		return -EIO;
+	
+	oi = (struct omfs_inode *) bh->b_data;
+	if (OMFS_I(inode)->state & OMFS_STATE_NEW)
+	{
+		memset(oi, 0, sizeof(struct omfs_header));
+		OMFS_I(inode)->state &= ~OMFS_STATE_NEW;
+	}
+
+	oi->head.self = cpu_to_be64(inode->i_ino);
+	if (S_ISDIR(inode->i_mode)) {
+		oi->type = OMFS_DIR;
+	} else if (S_ISREG(inode->i_mode)) {
+		oi->type = OMFS_FILE;
+	} else 
+		BUG();
+
+	oi->head.body_size = cpu_to_be32(sbi->sys_blocksize - 
+		sizeof(struct omfs_header));
+	oi->head.version = 1;
+	oi->head.type = OMFS_INODE_NORMAL;
+	oi->head.magic = OMFS_IMAGIC;
+	oi->size = cpu_to_be64(inode->i_size);
+
+	ctime = inode->i_ctime.tv_sec * 1000LL + 
+		((inode->i_ctime.tv_nsec + 999)/1000);
+	oi->ctime = cpu_to_be64(ctime);
+
+	if (omfs_update_checksums(oi, inode) != 0)
+		return -EIO;
+
+	mark_buffer_dirty(bh);
+	brelse(bh);
+
+	// if mirroring writes, copy to next mirror
+	for (i = sbi->mirrors; i > 0; i--)
+	{
+		int j;
+		int num_blks = sbi->sys_blocksize / inode->i_sb->s_blocksize;
+		for (j=0; j < num_blks; j++, block++)
+		{
+			bh = sb_bread(inode->i_sb, block);
+			if (!bh)
+				return -EIO;
+			bh2 = sb_bread(inode->i_sb, block + num_blks);
+			if (!bh2)
+			{
+				brelse(bh);
+				return -EIO;
+			}
+			memcpy(bh2->b_data, bh->b_data, bh->b_size);
+			mark_buffer_dirty(bh2);
+			brelse(bh);
+			brelse(bh2);
+		}
+	}
+
+	// do_sync?
+	return 0;
+}
+#endif
+
+void omfs_read_inode(struct inode *inode)
+{
+	struct omfs_inode *oi;
+	struct omfs_inode_info *oinf = OMFS_I(inode);
+	struct buffer_head *bh;
+	unsigned int block;
+	u64 ctime;
+	unsigned long nsecs;
+	ino_t ino = inode->i_ino;
+
+	// check against num_blocks
+	block = clus_to_blk(ino);
+	bh = sb_bread(inode->i_sb, block);
+	if (!bh) {
+		make_bad_inode(inode);
+		return;
+	}
+
+	oi = (struct omfs_inode *)bh->b_data;
+
+	// check self
+	if (ino != be64_to_cpu(oi->head.self)) {
+		make_bad_inode(inode);
+		return;
+	}
+
+	inode->i_uid = 0;
+	inode->i_gid = 0;
+
+	ctime = be64_to_cpu(oi->ctime);
+	nsecs = do_div(ctime, 1000) * 1000L;
+
+	inode->i_atime.tv_sec = ctime;
+	inode->i_mtime.tv_sec = ctime;
+	inode->i_ctime.tv_sec = ctime;
+	inode->i_atime.tv_nsec = nsecs;
+	inode->i_mtime.tv_nsec = nsecs;
+	inode->i_ctime.tv_nsec = nsecs;
+
+	oinf->state = 0;
+
+	if (oi->type == OMFS_DIR) {
+		inode->i_mode = S_IFDIR | S_IRUGO | S_IWUGO | S_IXUGO;
+		inode->i_op = &omfs_dir_inops;
+		inode->i_fop = &omfs_dir_operations;
+		inode->i_size = be32_to_cpu(oi->head.body_size) +
+			sizeof(struct omfs_header);
+	} else if (oi->type == OMFS_FILE) {
+		inode->i_mode = S_IFREG | S_IRUGO;
+		inode->i_mapping->a_ops = &omfs_aops;
+		inode->i_fop = &omfs_file_operations;
+		inode->i_size = be64_to_cpu(oi->size);
+	}
+	brelse(bh);
+}
+
+
+static void omfs_put_super(struct super_block *sb)
+{
+	struct omfs_sb_info *sbi = OMFS_SB(sb);
+	if (sbi)
+	{
+		kfree(sbi->imap);
+		kfree(sbi);
+	}
+	sb->s_fs_info = NULL;
+}
+
+static int omfs_statfs(struct super_block *s, struct kstatfs *buf)
+{
+	struct omfs_sb_info *sbi = OMFS_SB(s);
+	buf->f_type = OMFS_MAGIC;
+	buf->f_bsize = sbi->blocksize;
+	buf->f_blocks = sbi->num_blocks;
+	buf->f_files = sbi->num_blocks;
+	buf->f_namelen = OMFS_NAMELEN;
+
+	buf->f_bfree = buf->f_bavail = buf->f_ffree = 
+		omfs_count_free(s);
+	return 0;
+}
+
+struct super_operations omfs_sops = {
+	.alloc_inode	= omfs_alloc_inode,
+	.destroy_inode	= omfs_destroy_inode,
+#ifdef OMFS_WRITE
+	.write_inode	= omfs_write_inode, 
+#endif
+	.read_inode	= omfs_read_inode,
+	.put_super	= omfs_put_super,
+	.statfs		= omfs_statfs,
+};
+
+/*
+ * For Rio Karma, there is an on-disk free bitmap whose location is
+ * stored in the root block.  For ReplayTV, there is no such free bitmap
+ * so we have to walk the tree.  Both inodes and file data are allocated
+ * from the same map.  This array can be big (300k) so we allocate 
+ * in units of the blocksize.
+ */
+static int omfs_get_imap(struct super_block *sb)
+{
+	int bitmap_size;
+	int array_size;
+	int count;
+	struct omfs_sb_info *sbi = OMFS_SB(sb);
+	struct buffer_head *bh;
+	unsigned long **ptr;
+	sector_t block;
+
+	bitmap_size = (sbi->num_blocks + 7) / 8;
+	array_size = (bitmap_size + sb->s_blocksize - 1) / sb->s_blocksize;
+
+	printk(KERN_DEBUG "omfs: trying to alloc %d bytes\n", array_size);
+	sbi->imap_size = array_size;
+	sbi->imap = kzalloc(array_size, GFP_KERNEL);
+	if (!sbi->imap)
+		return -ENOMEM;
+
+	block = clus_to_blk(sbi->bitmap_ino);
+	ptr = sbi->imap;
+	for (count = bitmap_size; count > 0; count -= sb->s_blocksize) {
+		bh = sb_bread(sb, block++);
+		if (!bh)
+			goto nomem;
+		*ptr = kmalloc(sb->s_blocksize, GFP_KERNEL);
+		memcpy(*ptr, bh->b_data, sb->s_blocksize);
+		brelse(bh);
+		ptr ++;
+	}
+	return 0;
+nomem:
+	printk(KERN_DEBUG "died at %ld\n", block);
+	for (count=0; count<array_size; count++)
+	{
+		printk(KERN_DEBUG "Freeing %d\n", count);
+		kfree(sbi->imap[count]);
+	}
+	printk(KERN_DEBUG "Freeing imap\n");
+	kfree(sbi->imap);
+	sbi->imap = NULL;
+	return -ENOMEM;
+}
+
+static int omfs_fill_super(struct super_block *sb, void *data, int silent)
+{
+	struct buffer_head *bh=NULL, *bh2=NULL;
+	struct omfs_super_block *omfs_sb;
+	struct omfs_root_block *omfs_rb;
+	struct omfs_sb_info *sbi;
+	struct inode *root;
+	sector_t start;
+	int ret = 0;
+
+	sbi = kzalloc(sizeof(struct omfs_sb_info), GFP_KERNEL);
+	if (!sbi)
+		return -ENOMEM;
+	sb->s_fs_info = sbi;
+
+#ifndef OMFS_WRITE
+	sb->s_flags |= MS_RDONLY; 
+#endif
+	sb->s_maxbytes = 0xffffffff;
+
+	// We always operate on single sectors since OMFS partitions
+	// regularly use blocks larger than PAGE_SIZE
+	// (blocksize *could* be anything that is a factor of 
+	// sys_blocksize, however, if changing clus_to_blk)
+	sb_set_blocksize(sb, 0x200);
+
+	if (!(bh = sb_bread(sb, 0)))
+		goto out;
+
+	omfs_sb = (struct omfs_super_block *)bh->b_data;
+
+	if (be32_to_cpu(omfs_sb->magic) != OMFS_MAGIC) {
+		if (!silent)
+			printk(KERN_ERR "omfs: Invalid superblock (%x)\n",
+				   omfs_sb->magic);
+		goto out;
+	}
+	sb->s_magic = OMFS_MAGIC;
+
+	start = clus_to_blk(be64_to_cpu(omfs_sb->root_block));
+	if (!(bh2 = sb_bread(sb, start)))
+		goto out;
+
+	omfs_rb = (struct omfs_root_block *)bh2->b_data;
+	printk(KERN_DEBUG "omfs: volume: %s\n", omfs_rb->name);
+
+	sbi->num_blocks = be64_to_cpu(omfs_sb->num_blocks);
+	sbi->blocksize = be32_to_cpu(omfs_sb->blocksize);
+	sbi->mirrors = be32_to_cpu(omfs_sb->mirrors);
+	sbi->root_ino = be64_to_cpu(omfs_sb->root_block);
+	sbi->sys_blocksize = be32_to_cpu(omfs_sb->sys_blocksize);
+	sbi->bitmap_ino = be64_to_cpu(omfs_rb->bitmap);
+	sbi->clustersize = be32_to_cpu(omfs_rb->clustersize);
+
+	ret = omfs_get_imap(sb);
+	if (ret)
+		goto end;
+
+	sb->s_op = &omfs_sops;
+	root = iget(sb, be64_to_cpu(omfs_rb->root_dir));
+
+	sb->s_root = d_alloc_root(root);
+	if (!sb->s_root) {
+		iput(root);
+		goto out;
+	}
+	goto end;
+
+out:
+	ret = -EINVAL;
+
+end:
+	if (bh2)
+		brelse(bh2);
+	if (bh)
+		brelse(bh);
+	return ret;
+}
+
+static struct super_block *omfs_get_sb(struct file_system_type *fs_type,
+					   int flags, const char *dev_name,
+					   void *data)
+{
+	return get_sb_bdev(fs_type, flags, dev_name, data, omfs_fill_super);
+}
+
+static struct file_system_type omfs_fs_type = {
+	.owner = THIS_MODULE,
+	.name = "omfs",
+	.get_sb = omfs_get_sb,
+	.kill_sb = kill_block_super,
+	.fs_flags = FS_REQUIRES_DEV,
+};
+
+static int __init init_omfs_fs(void)
+{
+	int err = init_inodecache();
+	if (err)
+		goto out;
+
+	err = register_filesystem(&omfs_fs_type);
+	if (err)
+		destroy_inodecache();
+out:
+	return err;
+}
+
+static void __exit exit_omfs_fs(void)
+{
+	unregister_filesystem(&omfs_fs_type);
+	destroy_inodecache();
+}
+
+module_init(init_omfs_fs);
+module_exit(exit_omfs_fs);
diff --git a/fs/omfs/omfs.h b/fs/omfs/omfs.h
new file mode 100644
index 0000000..344cf6b
--- /dev/null
+++ b/fs/omfs/omfs.h
@@ -0,0 +1,140 @@
+#ifndef _OMFS_H
+#define _OMFS_H
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+
+#define OMFS_MAGIC 0xC2993D87
+#define OMFS_IMAGIC 0xD2
+
+#define OMFS_DIR 'D'
+#define OMFS_FILE 'F'
+#define OMFS_INODE_NORMAL 'e'
+#define OMFS_INODE_SYSTEM 's'
+#define OMFS_NAMELEN 256
+#define OMFS_DIR_START 0x1b8
+#define OMFS_EXTENT_START 0x1d0
+#define OMFS_EXTENT_CONT 0x40
+#define OMFS_XOR_COUNT 19
+
+#define OMFS_WRITE
+
+#define OMFS_STATE_NEW 1
+
+/* In-memory structures */
+struct omfs_sb_info {
+	u64 num_blocks;
+	u64 bitmap_ino;
+	u64 root_ino;
+	u32 blocksize;
+	u32 mirrors;
+	u32 sys_blocksize;
+	u32 clustersize;
+	unsigned long **imap;
+	int imap_size;
+};
+
+struct omfs_inode_info {
+	u8 state;	
+	struct inode vfs_inode;
+};
+
+/* On-disk structures */
+struct omfs_super_block {
+	char fill1[256];
+	__be64 root_block;
+	__be64 num_blocks;
+	__be32 magic;
+	__be32 blocksize;
+	__be32 mirrors;
+	__be32 sys_blocksize;
+};
+
+struct omfs_header {
+	__be64 self;
+	__be32 body_size;
+	__be16 crc;
+	char fill1[2];
+	u8 version;       
+	char type;
+	u8 magic;
+	u8 check_xor;
+	__be32 fill2;
+};
+
+struct omfs_root_block {
+	struct omfs_header head;
+	__be64 fill1;
+	__be64 num_blocks;
+	__be64 root_dir;
+	__be64 bitmap;
+	__be32 blocksize;
+	__be32 clustersize;
+	__be64 mirrors;
+	char name[OMFS_NAMELEN];
+};
+
+struct omfs_inode {
+	struct omfs_header head;
+	__be64 parent;
+	__be64 sibling;
+	__be64 ctime;
+	char fill1[35];
+	char type;
+	__be32 fill2;
+	char fill3[64];
+	char name[OMFS_NAMELEN];
+	__be64 size;
+};
+
+struct omfs_extent_entry {
+	__be64 cluster;
+	__be64 blocks;
+};
+	
+struct omfs_extent {
+	__be64 next;
+	__be32 extent_count;
+	__be32 fill;
+	struct omfs_extent_entry entry;
+};
+
+
+/* convert a cluster number to a 512-byte block number */
+static inline sector_t clus_to_blk(sector_t in)
+{
+	return in << 4;
+}
+
+static inline struct omfs_sb_info *OMFS_SB(struct super_block *sb)
+{
+	return sb->s_fs_info;
+}
+
+static inline struct omfs_inode_info *OMFS_I(struct inode *inode)
+{
+	return list_entry(inode, struct omfs_inode_info, vfs_inode);
+}
+
+/* bitmap.c */
+extern unsigned long omfs_count_free(struct super_block *sb);
+
+/* checksum.c */
+extern int omfs_update_checksums(struct omfs_inode *oi, struct inode *inode);
+
+/* dir.c */
+extern struct file_operations omfs_dir_operations;
+extern struct inode_operations omfs_dir_inops;
+
+/* file.c */
+extern struct file_operations omfs_file_operations;
+extern struct address_space_operations omfs_aops;
+extern int omfs_make_empty_file(struct inode *inode, struct super_block *sb);
+
+/* inode.c */
+extern void omfs_read_inode(struct inode *inode);
+extern struct inode *omfs_new_inode(struct inode *dir, int mode);
+extern int omfs_reserve_block(struct super_block *sb, sector_t block);
+
+#endif
diff --git a/fs/partitions/Kconfig b/fs/partitions/Kconfig
index deb25b6..f916ef1 100644
--- a/fs/partitions/Kconfig
+++ b/fs/partitions/Kconfig
@@ -225,4 +225,11 @@ config EFI_PARTITION
 	  were partitioned using EFI GPT.  Presently only useful on the
 	  IA-64 platform.
 
+config KARMA_PARTITION
+	bool "Karma Partition support"
+	depends on PARTITION_ADVANCED
+	help
+	  Say Y here if you would like to mount the Rio Karma MP3 player,
+          as it uses a proprietary partition table.
+
 #      define_bool CONFIG_ACORN_PARTITION_CUMANA y
diff --git a/fs/partitions/Makefile b/fs/partitions/Makefile
index 66d5cc2..42c7d38 100644
--- a/fs/partitions/Makefile
+++ b/fs/partitions/Makefile
@@ -17,3 +17,4 @@ obj-$(CONFIG_SUN_PARTITION) += sun.o
 obj-$(CONFIG_ULTRIX_PARTITION) += ultrix.o
 obj-$(CONFIG_IBM_PARTITION) += ibm.o
 obj-$(CONFIG_EFI_PARTITION) += efi.o
+obj-$(CONFIG_KARMA_PARTITION) += karma.o
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 8dc1822..ac10938 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -35,6 +35,7 @@
 #include "ibm.h"
 #include "ultrix.h"
 #include "efi.h"
+#include "karma.h"
 
 #ifdef CONFIG_BLK_DEV_MD
 extern void md_autodetect_dev(dev_t dev);
@@ -103,6 +104,9 @@ static int (*check_part[])(struct parsed
 #ifdef CONFIG_IBM_PARTITION
 	ibm_partition,
 #endif
+#ifdef CONFIG_KARMA_PARTITION
+	karma_partition,
+#endif
 	NULL
 };
  
diff --git a/fs/partitions/karma.c b/fs/partitions/karma.c
new file mode 100644
index 0000000..b4f5fed
--- /dev/null
+++ b/fs/partitions/karma.c
@@ -0,0 +1,57 @@
+/*
+ *  fs/partitions/karma.c
+ *  Rio Karma partition info.
+ *
+ *  Copyright (C) 2005 Bob Copeland (me@bobcopeland.com)
+ *  based on ofs.c
+ */
+
+#include "check.h"
+#include "karma.h"
+
+int karma_partition(struct parsed_partitions *state, struct block_device *bdev)
+{
+	int i;
+	int slot = 1;
+	Sector sect;
+	unsigned char *data;
+	struct disklabel {
+		u8 reserved[270];
+		struct d_partition {
+			__le32 res;
+			u8 fstype;
+			u8 res2[3];
+			__le32 offset;
+			__le32 size;
+		} partitions[2];
+		u8 blank[208];
+		__le16 magic;
+	} __attribute__((packed)) *label;
+	struct d_partition *p;
+
+	data = read_dev_sector(bdev, 0, &sect);
+	if (!data)
+		return -1;
+
+	label = (struct disklabel *) data;
+	if (le16_to_cpu(label->magic) != KARMA_LABEL_MAGIC) {
+		put_dev_sector(sect);
+		return 0;
+	}
+
+	p = label->partitions;
+	for (i = 0 ; i < 2; i++, p++) {
+		if (slot == state->limit)
+			break;
+
+		if (p->fstype == 0x4d && le32_to_cpu(p->size)) {
+			put_partition(state, slot, le32_to_cpu(p->offset),
+				le32_to_cpu(p->size));
+		}
+		slot++;
+	}
+	printk("\n");
+	put_dev_sector(sect);
+	return 1;
+}
+
diff --git a/fs/partitions/karma.h b/fs/partitions/karma.h
new file mode 100644
index 0000000..ecf7d3f
--- /dev/null
+++ b/fs/partitions/karma.h
@@ -0,0 +1,8 @@
+/*
+ *  fs/partitions/karma.h
+ */
+
+#define KARMA_LABEL_MAGIC		0xAB56
+
+int karma_partition(struct parsed_partitions *state, struct block_device *bdev);
+
