All of lore.kernel.org
 help / color / mirror / Atom feed
From: joern@logfs.org
To: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org,
	linux-mtd@lists.infradead.org
Cc: David Woodhouse <dwmw2@infradead.org>
Subject: [patch 15/15] fs/logfs/dev_mtd.c
Date: Tue, 01 Apr 2008 20:13:08 +0200	[thread overview]
Message-ID: <20080401181332.853833015@logfs.org> (raw)
In-Reply-To: 20080401181308.512473173@logfs.org

--- /dev/null	2008-03-30 12:15:48.586669308 +0200
+++ linux-2.6.24logfs/fs/logfs/dev_mtd.c	2008-04-01 19:44:47.991289121 +0200
@@ -0,0 +1,406 @@
+/*
+ * fs/logfs/dev_mtd.c	- Device access methods for MTD
+ *
+ * As should be obvious for Linux kernel code, license is GPLv2
+ *
+ * Copyright (c) 2005-2007 Joern Engel <joern@logfs.org>
+ */
+#include "logfs.h"
+#include <linux/completion.h>
+#include <linux/mount.h>
+
+#define PAGE_OFS(ofs) ((ofs) & (PAGE_SIZE-1))
+
+static struct vfsmount *mtd_mount __read_mostly;
+static struct kmem_cache *mtd_cache __read_mostly;
+
+static inline struct mtd_inode *mtd_inode(struct inode *inode)
+{
+	return container_of(inode, struct mtd_inode, vfs_inode);
+}
+
+static int mtd_read(struct super_block *sb, loff_t ofs, size_t len, void *buf)
+{
+	struct mtd_inode *mi = logfs_super(sb)->s_mtd;
+	struct mtd_info *mtd = mi->mtd;
+	size_t retlen;
+	int ret;
+
+	ret = mtd->read(mtd, ofs, len, &retlen, buf);
+	BUG_ON(ret == -EINVAL);
+	if (ret)
+		return ret;
+
+	/* Not sure if we should loop instead. */
+	if (retlen != len)
+		return -EIO;
+
+	return 0;
+}
+
+static int mtd_write(struct super_block *sb, loff_t ofs, size_t len, void *buf)
+{
+	struct logfs_super *super = logfs_super(sb);
+	struct mtd_inode *mi = super->s_mtd;
+	struct mtd_info *mtd = mi->mtd;
+	size_t retlen;
+	loff_t page_start, page_end;
+	int ret;
+
+	if (super->s_flags & LOGFS_SB_FLAG_RO)
+		return -EROFS;
+
+	BUG_ON((ofs >= mtd->size) || (len > mtd->size - ofs));
+	BUG_ON(ofs != (ofs >> super->s_writeshift) << super->s_writeshift);
+	BUG_ON(len > PAGE_CACHE_SIZE);
+	page_start = ofs & PAGE_CACHE_MASK;
+	page_end = PAGE_CACHE_ALIGN(ofs + len) - 1;
+	ret = mtd->write(mtd, ofs, len, &retlen, buf);
+	if (ret || (retlen != len))
+		return -EIO;
+
+	return 0;
+}
+
+/*
+ * For as long as I can remember (since about 2001) mtd->erase has been an
+ * asynchronous interface lacking the first driver to actually use the
+ * asynchronous properties.  So just to prevent the first implementor of such
+ * a thing from breaking logfs in 2350, we do the usual pointless dance to
+ * declare a completion variable and wait for completion before returning
+ * from mtd_erase().  What an excercise in futility!
+ */
+static void logfs_erase_callback(struct erase_info *ei)
+{
+	complete((struct completion *)ei->priv);
+}
+
+static int mtd_erase(struct super_block *sb, loff_t ofs, size_t len)
+{
+	struct mtd_inode *mi = logfs_super(sb)->s_mtd;
+	struct mtd_info *mtd = mi->mtd;
+	struct erase_info ei;
+	DECLARE_COMPLETION_ONSTACK(complete);
+	int ret;
+
+	BUG_ON(len % mtd->erasesize);
+
+	if (logfs_super(sb)->s_flags & LOGFS_SB_FLAG_RO)
+		return -EROFS;
+
+	memset(&ei, 0, sizeof(ei));
+	ei.mtd = mtd;
+	ei.addr = ofs;
+	ei.len = len;
+	ei.callback = logfs_erase_callback;
+	ei.priv = (long)&complete;
+	ret = mtd->erase(mtd, &ei);
+	if (ret)
+		return -EIO;
+
+	wait_for_completion(&complete);
+	if (ei.state != MTD_ERASE_DONE)
+		return -EIO;
+	return 0;
+}
+
+static void mtd_sync(struct super_block *sb)
+{
+	struct mtd_inode *mi = logfs_super(sb)->s_mtd;
+	struct mtd_info *mtd = mi->mtd;
+
+	if (mtd->sync)
+		mtd->sync(mtd);
+}
+
+static s64 mtd_find_sb(struct super_block *sb)
+{
+	struct mtd_inode *mi = logfs_super(sb)->s_mtd;
+	struct mtd_info *mtd = mi->mtd;
+	s64 ofs = 0;
+
+	if (!mtd->block_isbad)
+		return 0;
+
+	while (mtd->block_isbad(mtd, ofs)) {
+		ofs += mtd->erasesize;
+		if (ofs > mtd->size)
+			return -EIO;
+	}
+	return ofs;
+}
+
+static int map_read(struct super_block *sb, loff_t ofs, size_t len, void *buf)
+{
+	struct mtd_inode *mi = logfs_super(sb)->s_mtd;
+	struct inode *inode = &mi->vfs_inode;
+	struct page *page;
+	void *buf0;
+	unsigned long page_ofs, cplen;
+	int err;
+
+	while (len) {
+		page = find_or_create_page(inode->i_mapping, ofs>>PAGE_SHIFT,
+				GFP_NOIO);
+		if (!page)
+			return -ENOMEM;
+
+		if (!PageUptodate(page)) {
+			buf0 = kmap(page);
+			err = mtd_read(sb, ofs&PAGE_MASK, PAGE_SIZE, buf0);
+			kunmap(page);
+			if (err) {
+				unlock_page(page);
+				page_cache_release(page);
+				return err;
+			}
+			SetPageUptodate(page);
+		}
+
+		page_ofs = PAGE_OFS(ofs);
+		cplen = min(PAGE_SIZE - page_ofs, (unsigned long)len);
+
+		buf0 = kmap_atomic(page, KM_USER0);
+		memcpy(buf, buf0 + page_ofs, cplen);
+		kunmap_atomic(buf0, KM_USER0);
+		unlock_page(page);
+		page_cache_release(page);
+
+		ofs += cplen;
+		buf += cplen;
+		len -= cplen;
+	}
+	return 0;
+}
+
+#ifdef CACHE_WRITES
+/* This variant is about 4% slower than the write-invalidate variant */
+static int map_write(struct super_block *sb, loff_t ofs, size_t len, void *buf)
+{
+	struct mtd_inode *mi = logfs_super(sb)->s_mtd;
+	struct inode *inode = &mi->vfs_inode;
+	struct page *page;
+	void *buf0;
+	unsigned long page_ofs, cplen;
+	int err;
+
+	while (len) {
+		page = find_or_create_page(inode->i_mapping, ofs>>PAGE_SHIFT,
+				GFP_NOIO);
+		if (!page)
+			return -ENOMEM;
+
+		if (!PageUptodate(page) &&
+				(PAGE_OFS(ofs) || (len < PAGE_SIZE))) {
+			buf0 = kmap(page);
+			err = mtd_read(sb, ofs&PAGE_MASK, PAGE_SIZE, buf0);
+			kunmap(page);
+			if (err) {
+				unlock_page(page);
+				page_cache_release(page);
+				return err;
+			}
+			SetPageUptodate(page);
+		}
+
+		page_ofs = PAGE_OFS(ofs);
+		cplen = min(PAGE_SIZE - page_ofs, (unsigned long)len);
+
+		buf0 = kmap_atomic(page, KM_USER0);
+		memcpy(buf0 + page_ofs, buf, cplen);
+		kunmap_atomic(buf0, KM_USER0);
+
+		buf0 = kmap(page);
+		err = mtd_write(sb, ofs, cplen, buf0 + page_ofs);
+		kunmap(page);
+		unlock_page(page);
+		page_cache_release(page);
+		if (err)
+			return err;
+
+		ofs += cplen;
+		buf += cplen;
+		len -= cplen;
+	}
+	return 0;
+}
+#else
+static int map_write(struct super_block *sb, loff_t ofs, size_t len, void *buf)
+{
+	struct mtd_inode *mi = logfs_super(sb)->s_mtd;
+	struct inode *inode = &mi->vfs_inode;
+	struct page *page;
+	unsigned long page_ofs, cplen;
+	int err;
+
+	err = mtd_write(sb, ofs, len, buf);
+	if (err)
+		return err;
+
+	while (len) {
+		page = find_get_page(inode->i_mapping, ofs>>PAGE_SHIFT);
+		if (page) {
+			ClearPageUptodate(page);
+			page_cache_release(page);
+		}
+
+		page_ofs = PAGE_OFS(ofs);
+		cplen = min(PAGE_SIZE - page_ofs, (unsigned long)len);
+
+		ofs += cplen;
+		buf += cplen;
+		len -= cplen;
+	}
+	return 0;
+}
+#endif
+
+static int map_erase(struct super_block *sb, loff_t ofs, size_t len)
+{
+	struct mtd_inode *mi = logfs_super(sb)->s_mtd;
+	struct inode *inode = &mi->vfs_inode;
+	struct page *page;
+	int err;
+
+	BUG_ON(PAGE_OFS(ofs) || PAGE_OFS(len));
+
+	err = mtd_erase(sb, ofs, len);
+	if (err)
+		return err;
+
+	while (len) {
+		page = find_get_page(inode->i_mapping, ofs>>PAGE_SHIFT);
+		if (page) {
+			ClearPageUptodate(page);
+			page_cache_release(page);
+		}
+
+		ofs += PAGE_SIZE;
+		len -= PAGE_SIZE;
+	}
+	return 0;
+}
+
+static const struct logfs_device_ops mtd_devops = {
+	.find_sb	= mtd_find_sb,
+	.read		= map_read,
+	.write		= map_write,
+	.erase		= map_erase,
+	.sync		= mtd_sync,
+};
+
+int logfs_get_sb_mtd(struct file_system_type *type, int flags,
+		int mtdnr, struct vfsmount *mnt)
+{
+	struct inode *inode;
+
+	inode = iget_locked(mtd_mount->mnt_sb, mtdnr);
+	if (!inode)
+		return -ENOMEM;
+
+	if (inode->i_state & I_NEW) {
+		inode->i_mode = S_IFCHR;
+		inode->i_rdev = MKDEV(MTD_CHAR_MAJOR, mtdnr);
+		mtd_inode(inode)->mtd = get_mtd_device(NULL, mtdnr);
+		if (!mtd_inode(inode)->mtd) {
+			make_bad_inode(inode);
+			unlock_new_inode(inode);
+			iput(inode);
+			return -EINVAL;
+		}
+		unlock_new_inode(inode);
+	}
+
+	mtd_inode(inode)->openers++;
+
+	return logfs_get_sb_device(type, flags, mtd_inode(inode), NULL,
+			&mtd_devops, mnt);
+}
+
+void logfs_put_mtd(struct mtd_inode *mi)
+{
+	if (mi) {
+		if (!--mi->openers)
+			truncate_inode_pages(mi->vfs_inode.i_mapping, 0);
+		iput(&mi->vfs_inode);
+	}
+}
+
+static struct inode *mtd_alloc_inode(struct super_block *sb)
+{
+	struct mtd_inode *mi = kmem_cache_alloc(mtd_cache, GFP_KERNEL);
+
+	if (!mi)
+		return NULL;
+	return &mi->vfs_inode;
+}
+
+static void mtd_destroy_inode(struct inode *inode)
+{
+	struct mtd_inode *mi = mtd_inode(inode);
+
+	put_mtd_device(mi->mtd);
+	kmem_cache_free(mtd_cache, mi);
+}
+
+static const struct super_operations mtd_sops = {
+	.alloc_inode	= mtd_alloc_inode,
+	.destroy_inode	= mtd_destroy_inode,
+};
+
+static int mtd_get_sb(struct file_system_type *fs_type, int flags,
+		const char *dev_name, void *data, struct vfsmount *mnt)
+{
+	return get_sb_pseudo(fs_type, "mtd:", NULL, 0x6D746400, mnt);
+}
+
+static void init_once(struct kmem_cache *cache, void *_mi)
+{
+	struct mtd_inode *mi = _mi;
+
+	mi->mtd = NULL;
+	mi->openers = 0;
+	inode_init_once(&mi->vfs_inode);
+}
+
+static struct file_system_type mtd_fs_type = {
+	.name		= "mtd",
+	.get_sb		= mtd_get_sb,
+	.kill_sb	= kill_anon_super,
+};
+
+static int __init logfs_mtd_init(void)
+{
+	int err;
+
+	mtd_cache = kmem_cache_create("mtd_cache", sizeof(struct mtd_inode), 0,
+			(SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
+			 SLAB_MEM_SPREAD|SLAB_PANIC),
+			init_once);
+	if (!mtd_cache)
+		return -ENOMEM;
+
+	err = register_filesystem(&mtd_fs_type);
+	if (err)
+		goto out1;
+
+	mtd_mount = kern_mount(&mtd_fs_type);
+	err = PTR_ERR(mtd_mount);
+	if (IS_ERR(mtd_mount))
+		goto out2;
+
+	return 0;
+out2:
+	unregister_filesystem(&mtd_fs_type);
+out1:
+	kmem_cache_destroy(mtd_cache);
+	return err;
+}
+
+static void __exit logfs_mtd_exit(void)
+{
+	unregister_filesystem(&mtd_fs_type);
+	kmem_cache_destroy(mtd_cache);
+}
+
+fs_initcall(logfs_mtd_init); /* FIXME: remove */

  parent reply	other threads:[~2008-04-03 17:29 UTC|newest]

Thread overview: 85+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-04-01 18:13 [patch 0/15] LogFS take five joern
2008-04-01 18:13 ` joern
2008-04-01 18:13 ` [patch 4/15] fs/logfs/compr.c joern
2008-04-10 14:13   ` Arnd Bergmann
2008-04-10 14:13     ` Arnd Bergmann
2008-04-10 14:13     ` Arnd Bergmann
2008-04-11 10:41     ` Jörn Engel
2008-04-11 10:41       ` Jörn Engel
2008-04-01 18:13 ` joern [this message]
2008-04-01 18:13 ` [patch 2/15] fs/logfs/logfs_abi.h joern
2008-04-08  0:24   ` Arnd Bergmann
2008-04-08  0:24     ` Arnd Bergmann
2008-04-08  0:24     ` Arnd Bergmann
2008-04-08  9:39     ` Jörn Engel
2008-04-08  9:39       ` Jörn Engel
2008-04-08  9:39       ` Jörn Engel
2008-04-08 21:52       ` Andres Salomon
2008-04-08 21:52         ` Andres Salomon
2008-04-09 12:08         ` Jörn Engel
2008-04-09 12:08           ` Jörn Engel
2008-04-09 12:08           ` Jörn Engel
2008-04-01 18:13 ` [patch 12/15] fs/logfs/segment.c joern
2008-04-01 18:13 ` [patch 10/15] fs/logfs/memtree.c joern
2008-04-10 14:07   ` Arnd Bergmann
2008-04-10 14:07     ` Arnd Bergmann
2008-04-10 14:07     ` Arnd Bergmann
2008-04-11 10:37     ` Jörn Engel
2008-04-11 10:37       ` Jörn Engel
2008-04-11 10:37       ` Jörn Engel
2008-04-01 18:13 ` [patch 7/15] fs/logfs/gc.c joern
2008-04-01 18:13 ` [patch 13/15] fs/logfs/super.c joern
2008-04-01 18:13 ` [patch 1/15] Makefiles and Kconfig joern
2008-04-07  8:28   ` Christian Borntraeger
2008-04-07  8:28     ` Christian Borntraeger
2008-04-07  8:40     ` Jörn Engel
2008-04-07  8:40       ` Jörn Engel
2008-04-07  8:40       ` Jörn Engel
2008-04-08  0:30   ` Arnd Bergmann
2008-04-08  0:30     ` Arnd Bergmann
2008-04-08  8:33     ` Jörn Engel
2008-04-08  8:33       ` Jörn Engel
2008-04-08  8:33       ` Jörn Engel
2008-04-08 13:41       ` Arnd Bergmann
2008-04-08 13:41         ` Arnd Bergmann
2008-04-08 13:41         ` Arnd Bergmann
2008-04-08 13:52         ` Jörn Engel
2008-04-08 13:52           ` Jörn Engel
2008-04-08 13:52           ` Jörn Engel
2008-04-01 18:13 ` [patch 9/15] fs/logfs/journal.c joern
2008-04-01 18:13 ` [patch 14/15] fs/logfs/dev_bdev.c joern
2008-04-01 18:13 ` [patch 11/15] fs/logfs/readwrite.c joern
2008-04-01 18:13 ` [patch 5/15] fs/logfs/dir.c joern
2008-04-04  6:22   ` Kyungmin Park
2008-04-04  6:22     ` Kyungmin Park
2008-04-01 18:13 ` [patch 3/15] fs/logfs/logfs.h joern
2008-04-08  0:35   ` Arnd Bergmann
2008-04-08  0:35     ` Arnd Bergmann
2008-04-08  0:35     ` Arnd Bergmann
2008-04-08  9:41     ` Jörn Engel
2008-04-08  9:41       ` Jörn Engel
2008-04-08  9:41       ` Jörn Engel
2008-04-01 18:13 ` [patch 8/15] fs/logfs/inode.c joern
2008-04-04  6:57   ` Kyungmin Park
2008-04-04  6:57     ` Kyungmin Park
2008-04-07 11:12     ` Jörn Engel
2008-04-07 11:12       ` Jörn Engel
2008-04-07 11:12       ` Jörn Engel
2008-04-01 18:13 ` [patch 6/15] fs/logfs/file.c joern
2008-04-03 17:13 ` [patch 0/15] LogFS take five^Wsix Jörn Engel
2008-04-03 17:13   ` Jörn Engel
2008-04-03 17:13   ` Jörn Engel
2008-04-04 11:46 ` [patch 0/15] LogFS take five Jens Axboe
2008-04-04 11:46   ` Jens Axboe
2008-04-07  8:22   ` Jörn Engel
2008-04-07  8:22     ` Jörn Engel
2008-04-07  8:22     ` Jörn Engel
2008-04-07  8:28     ` Jens Axboe
2008-04-07  8:28       ` Jens Axboe
2008-04-07  8:28       ` Jens Axboe
2008-04-07  9:10       ` Jörn Engel
2008-04-07  9:10         ` Jörn Engel
2008-04-07  9:10         ` Jörn Engel
2008-04-07  9:17         ` Jens Axboe
2008-04-07  9:17           ` Jens Axboe
2008-04-07  9:17           ` Jens Axboe

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080401181332.853833015@logfs.org \
    --to=joern@logfs.org \
    --cc=dwmw2@infradead.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mtd@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.