Skip to contentSkip to conversation

exofs for 2.6.30 (really)

PATCH In review Boaz Harrosh 2 participants 12 messages Apr 1, 2009 – Apr 2, 2009

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

cover exofs for 2.6.30 (really)

Posting the final exofs patchset for the Linux 2.6.30 merge window.

Unless something critical is found, any new comments, clean-ups, enhancements, I will apply ontop of this code for the next Kernel. So please do comment away.

I have squashed all comments changes and fixes, including Randy Dunlap's patch into their respective patch below. Attached are the grand diff from last time with annotations below important changes about what was changed.

Thank you for every one that participated and help to make this a better code.

exofs is a fully usable and exportable filesystem by now. About stability, well it was not used that much.

These patches are available in the git repository at:

git://git.open-osd.org/linux-open-osd.git for-linus

Boaz Harrosh (9):
exofs: Kbuild, Headers and osd utils
exofs: file and file_inode operations
exofs: symlink_inode and fast_symlink_inode operations
exofs: address_space_operations
exofs: dir_inode and directory operations
exofs: super_operations and file_system_type
exofs: export_operations
exofs: Documentation
fs: Add exofs to Kernel build

 Documentation/filesystems/exofs.txt |  176 +++++
 fs/Kconfig                          |    2 +
 fs/Makefile                         |    1 +
 fs/exofs/BUGS                       |    3 +
 fs/exofs/Kbuild                     |   16 +
 fs/exofs/Kconfig                    |   13 +
 fs/exofs/common.h                   |  184 +++++
 fs/exofs/dir.c                      |  672 ++++++++++++++++++
 fs/exofs/exofs.h                    |  180 +++++
 fs/exofs/file.c                     |   87 +++
 fs/exofs/inode.c                    | 1303 +++++++++++++++++++++++++++++++++++
 fs/exofs/namei.c                    |  342 +++++++++
 fs/exofs/osd.c                      |  153 ++++
 fs/exofs/super.c                    |  584 ++++++++++++++++
 fs/exofs/symlink.c                  |   57 ++
 15 files changed, 3773 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/filesystems/exofs.txt
 create mode 100644 fs/exofs/BUGS
 create mode 100644 fs/exofs/Kbuild
 create mode 100644 fs/exofs/Kconfig
 create mode 100644 fs/exofs/common.h
 create mode 100644 fs/exofs/dir.c
 create mode 100644 fs/exofs/exofs.h
 create mode 100644 fs/exofs/file.c
 create mode 100644 fs/exofs/inode.c
 create mode 100644 fs/exofs/namei.c
 create mode 100644 fs/exofs/osd.c
 create mode 100644 fs/exofs/super.c
 create mode 100644 fs/exofs/symlink.c

Boaz

See comments embedded inside the patch

git diff --stat -p oo-experimental HEAD -- fs/exofs/

 fs/exofs/common.h |    5 +--
 fs/exofs/dir.c    |    3 +-
 fs/exofs/exofs.h  |   14 +++-----
 fs/exofs/file.c   |   11 +++---
 fs/exofs/inode.c  |   89 ++++++++++++++++++++++++++++-------------------------
 fs/exofs/super.c  |   11 ++++--
 6 files changed, 69 insertions(+), 64 deletions(-)
fs/exofs/common.h +2 -3
index 8a56338..24667ee 100644
@@ -63,9 +63,8 @@
  * Object IDs 0, 1, and 2 are always in use (see above defines).
  */
 enum {
-	EXOFS_UINT64_MAX = (~0LL),
-	EXOFS_MAX_INO_ID = (sizeof(ino_t) * 8 == 64) ? EXOFS_UINT64_MAX :
-					(1LL << (sizeof(ino_t) * 8 - 1)),
+	EXOFS_MAX_INO_ID = (sizeof(ino_t) * 8 == 64) ? ULLONG_MAX :
+					(1ULL << (sizeof(ino_t) * 8ULL - 1ULL)),
 	EXOFS_MAX_ID	 = (EXOFS_MAX_INO_ID - 1 - EXOFS_OBJ_OFF),
 };
 

For now ULLONG_MAX == UINT64_MAX until 128 bit machines come up. Perhaps in future I will submit a patch to kernel.h that adds:
UINT64_MAX, UINT32_MAX, UINT16_MAX, and UINT8_MAX in a platform independent way

fs/exofs/dir.c +2 -1
index 55ebbb1..65b0c8c 100644
@@ -46,6 +46,7 @@ static inline void exofs_put_page(struct page *page)
 	page_cache_release(page);
 }
 
+/* Accesses dir's inode->i_size must be called under inode lock */
 static inline unsigned long dir_pages(struct inode *inode)
 {
 	return (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
@@ -53,7 +54,7 @@ static inline unsigned long dir_pages(struct inode *inode)
 
 static unsigned exofs_last_byte(struct inode *inode, unsigned long page_nr)
 {
-	unsigned last_byte = inode->i_size;
+	loff_t last_byte = inode->i_size;
 
 	last_byte -= page_nr << PAGE_CACHE_SHIFT;
 	if (last_byte > PAGE_CACHE_SIZE)
fs/exofs/exofs.h +1 -1
index da1397a..0fd4c78 100644
@@ -47,7 +47,7 @@
 	printk(KERN_NOTICE "exofs @%s:%d: " fmt, __func__, __LINE__, ##a)
 #else
 #define EXOFS_DBGMSG(fmt, a...) \
-	do {} while (0)
+	do { if (0) printk(fmt, ##a); } while (0)
 #endif
 
 /* u64 has problems with printk this will cast it to unsigned long long */

Here I also let compile EXOFS_DBGMSG even if OFF. To catch compilation errors

@@ -89,22 +89,22 @@ struct exofs_i_info {

static inline int obj_2bcreated(struct exofs_i_info *oi) {
- return test_bit(OBJ_2BCREATED, &(oi->i_flags));
+ return test_bit(OBJ_2BCREATED, &oi->i_flags);
}

static inline void set_obj_2bcreated(struct exofs_i_info *oi) {
- set_bit(OBJ_2BCREATED, &(oi->i_flags));
+ set_bit(OBJ_2BCREATED, &oi->i_flags);
}

static inline int obj_created(struct exofs_i_info *oi) {
- return test_bit(OBJ_CREATED, &(oi->i_flags));
+ return test_bit(OBJ_CREATED, &oi->i_flags);
}

static inline void set_obj_created(struct exofs_i_info *oi) {
- set_bit(OBJ_CREATED, &(oi->i_flags));
+ set_bit(OBJ_CREATED, &oi->i_flags);
}

int __exofs_wait_obj_created(struct exofs_i_info *oi);
@@ -173,10 +173,6 @@ extern const struct address_space_operations exofs_aops;
extern const struct inode_operations exofs_dir_inode_operations; extern const struct inode_operations exofs_special_inode_operations;

-/* super.c */
-extern const struct super_operations exofs_sops;
-extern const struct export_operations exofs_export_ops;
-
/* symlink.c */
extern const struct inode_operations exofs_symlink_inode_operations; extern const struct inode_operations exofs_fast_symlink_inode_operations;

fs/exofs/file.c +6 -5
index 2712f68..6ed7fe4 100644
@@ -45,17 +45,18 @@ static int exofs_release_file(struct inode *inode, struct file *filp)
 static int exofs_file_fsync(struct file *filp, struct dentry *dentry,
 			    int datasync)
 {
-	int ret1, ret2;
+	int ret;
 	struct address_space *mapping = filp->f_mapping;
 
-	ret1 = filemap_write_and_wait(mapping);
+	ret = filemap_write_and_wait(mapping);
+	if (ret)
+		return ret;
+
 	/*Note: file_fsync below also calles sync_blockdev, which is a no-op
 	 *      for exofs, but other then that it does sync_inode and
 	 *      sync_superblock which is what we need here.
 	 */
-	ret2 = file_fsync(filp, dentry, datasync);
-
-	return ret1 ? ret1 : ret2;
+	return file_fsync(filp, dentry, datasync);
 }
 
 static int exofs_flush(struct file *file, fl_owner_t id)

As noted by Andrew, timeouts here can kill you.

fs/exofs/inode.c +16 -20
index b77c197..ba8d9fa 100644
@@ -52,7 +52,7 @@ struct page_collect {
 	struct bio *bio;
 	unsigned nr_pages;
 	unsigned long length;
-	long pg_first;
+	loff_t pg_first; /* keep 64bit also in 32-arches */
 };
 
 static void _pcol_init(struct page_collect *pcol, unsigned expected_pages,
@@ -161,8 +161,9 @@ static void update_write_page(struct page *page, int ret)
 	end_page_writeback(page);
 }
 
-static int _readpage(struct page *page, bool is_sync);
-
+/* Called at the end of reads, to optionally unlock pages and update their
+ * status.
+ */
 static int __readpages_done(struct osd_request *or, struct page_collect *pcol,
 			    bool do_unlock)
 {
@@ -183,35 +184,30 @@ static int __readpages_done(struct osd_request *or, struct page_collect *pcol,
 		good_bytes = pcol->length - resid;
 
 	EXOFS_DBGMSG("readpages_done(0x%lx) good_bytes=0x%llx"
-		     " length=0x%zx nr_pages=%u\n",
+		     " length=0x%lx nr_pages=%u\n",
 		     pcol->inode->i_ino, _LLU(good_bytes), pcol->length,
 		     pcol->nr_pages);
 
 	__bio_for_each_segment(bvec, pcol->bio, i, 0) {
 		struct page *page = bvec->bv_page;
 		struct inode *inode = page->mapping->host;
+		int page_stat;
 
 		if (inode != pcol->inode)
 			continue; /* osd might add more pages at end */
 
-		if ((length < good_bytes) || (i == 0)) {
-			ret = update_read_page(page, (i == 0) ? ret : 0);
-			if (do_unlock)
-				unlock_page(page);
-			EXOFS_DBGMSG("    readpages_done(0x%lx, 0x%lx)\n",
-				     inode->i_ino, page->index);
-		} else {
-			/* can not happen on single sync_readpage */
-			BUG_ON(!do_unlock);
+		if (likely(length < good_bytes))
+			page_stat = 0;
+		else
+			page_stat = ret;
 
-			/* try a single page read and only then it is
-			 * marked as SetPageError()
-			 */
-			EXOFS_ERR("    readpages_done(0x%lx, 0x%lx)"
-				  " bad_bytes\n", inode->i_ino, page->index);
-			_readpage(page, false);
-		}
+		EXOFS_DBGMSG("    readpages_done(0x%lx, 0x%lx) %s\n",
+			  inode->i_ino, page->index,
+			  page_stat ? "bad_bytes" : "good_bytes");
 
+		ret = update_read_page(page, page_stat);
+		if (do_unlock)
+			unlock_page(page);
 		length += bvec->bv_len;
 	}
 

What happened above was: Before I wanted to retry and read page-by-page those pages that failed. (Doing BLOCK_PC commands kind of fails early without retries). This can not work as it is, because current code will issue all commands GFP_KERNEL but the callback is called from interupt. (It can be fixed but not so trivially). Also a more detailed analysis should be preformed on when we can retry and when we should not.

Leave this fixture on TODO status.
(It was actually failing in tests)

@@ -220,6 +216,7 @@ static int __readpages_done(struct osd_request *or, struct page_collect *pcol,
return ret;
}

+/* callback of async reads */
static void readpages_done(struct osd_request *or, void *p)
{
struct page_collect *pcol = p;
@@ -289,7 +286,7 @@ static int read_exec(struct page_collect *pcol, bool is_sync)

atomic_inc(&pcol->sbi->s_curr_pending);

- EXOFS_DBGMSG("read_exec obj=0x%llx start=0x%llx length=0x%zx\n",
+ EXOFS_DBGMSG("read_exec obj=0x%llx start=0x%llx length=0x%lx\n",
obj.id, _LLU(i_start), pcol->length);

/* pages ownership was passed to pcol_copy */
@@ -305,6 +302,13 @@ err:
return ret;
}

+/* readpage_strip is called either directly from readpage() or by the VFS from
+ * within read_cache_pages(), to add one more page to be read. It will try to
+ * collect as many contiguous pages as posible. If a discontinuity is
+ * encountered, or it runs out of resources, it will submit the previous segment
+ * and will start a new collection. Eventually caller must submit the last
+ * segment if present.
+ */
static int readpage_strip(void *data, struct page *page)
{
struct page_collect *pcol = data;
@@ -372,7 +376,7 @@ try_again:
ret = pcol_add_page(pcol, page, len);
if (ret) {
EXOFS_DBGMSG("Failed pcol_add_page pages[i]=%p "
- "this_len=0x%zx nr_pages=%u length=0x%zx\n",
+ "this_len=0x%zx nr_pages=%u length=0x%lx\n",
page, len, pcol->nr_pages, pcol->length);

/* split the request, and start again with current page */
@@ -436,8 +440,7 @@ static int exofs_readpage(struct file *file, struct page *page)
return _readpage(page, false);
}

-static int exofs_writepage(struct page *page, struct writeback_control *wbc2); -
+/* Callback for osd_write. All writes are asynchronouse */
static void writepages_done(struct osd_request *or, void *p)
{
struct page_collect *pcol = p;
@@ -460,32 +463,27 @@ static void writepages_done(struct osd_request *or, void *p)
good_bytes = pcol->length - resid;

EXOFS_DBGMSG("writepages_done(0x%lx) good_bytes=0x%llx"
- " length=0x%zx nr_pages=%u\n",
+ " length=0x%lx nr_pages=%u\n",
pcol->inode->i_ino, _LLU(good_bytes), pcol->length, pcol->nr_pages);

__bio_for_each_segment(bvec, pcol->bio, i, 0) {
struct page *page = bvec->bv_page; struct inode *inode = page->mapping->host;
+ int page_stat;

if (inode != pcol->inode)
continue; /* osd might add more pages to a bio */

- if ((length < good_bytes) || (i == 0)) {
- update_write_page(page, ret);
- unlock_page(page);
- EXOFS_DBGMSG(" writepages_done(0x%lx, 0x%lx)"
- " good_bytes ret=%d\n",
- inode->i_ino, page->index, ret);
- } else {
- /* try a single page write and only then it is
- * marked as SetPageError()
- */
- EXOFS_ERR(" writepages_done(0x%lx, 0x%lx)"
- " bad_bytes\n", inode->i_ino, page->index);
+ if (likely(length < good_bytes))
+ page_stat = 0;
+ else
+ page_stat = ret;

- exofs_writepage(page, NULL);
- }
+ update_write_page(page, page_stat);
+ unlock_page(page);
+ EXOFS_DBGMSG(" writepages_done(0x%lx, 0x%lx) status=%d\n",
+ inode->i_ino, page->index, page_stat);

length += bvec->bv_len;
}

Same thing as above but for writes.

@@ -532,7 +530,7 @@ static int write_exec(struct page_collect *pcol)
}

atomic_inc(&pcol->sbi->s_curr_pending);
- EXOFS_DBGMSG("write_exec(0x%lx, 0x%lx) start=0x%llx length=0x%zx\n",
+ EXOFS_DBGMSG("write_exec(0x%lx, 0x%llx) start=0x%llx length=0x%lx\n",
pcol->inode->i_ino, pcol->pg_first, _LLU(i_start), pcol->length);
/* pages ownership was passed to pcol_copy */
@@ -547,6 +545,13 @@ err:
return ret;
}

+/* writepage_strip is called either directly from writepage() or by the VFS from
+ * within write_cache_pages(), to add one more page to be written to storage.
+ * It will try to collect as many contiguous pages as possible. If a
+ * discontinuity is encountered or it runs out of resources it will submit the
+ * previous segment and will start a new collection.
+ * Eventually caller must submit the last segment if present.
+ */
static int writepage_strip(struct page *page,
struct writeback_control *wbc_unused, void *data)
{
@@ -609,7 +614,7 @@ try_again:
ret = pcol_add_page(pcol, page, len);
if (unlikely(ret)) {
EXOFS_DBGMSG("Failed pcol_add_page "
- "nr_pages=%u total_length=0x%zx\n",
+ "nr_pages=%u total_length=0x%lx\n",
pcol->nr_pages, pcol->length);

/* split the request, next loop will start again */

fs/exofs/super.c +7 -4
index 8a07d6d..9f1985e 100644
@@ -194,6 +194,8 @@ static void destroy_inodecache(void)
 /******************************************************************************
  * SUPERBLOCK FUNCTIONS
  *****************************************************************************/
+static const struct super_operations exofs_sops;
+static const struct export_operations exofs_export_ops;
 
 /*
  * Write the superblock to the OSD
@@ -427,8 +429,8 @@ static int exofs_statfs(struct dentry *dentry, struct kstatfs *buf)
 		ATTR_DEF(OSD_APAGE_PARTITION_INFORMATION,
 			OSD_ATTR_PI_USED_CAPACITY, sizeof(__be64)),
 	};
-	uint64_t capacity = ~0;
-	uint64_t used = ~0;
+	uint64_t capacity = ULLONG_MAX;
+	uint64_t used = ULLONG_MAX;
 	struct osd_request *or;
 	uint8_t cred_a[OSD_CAP_LEN];
 	int ret;
@@ -475,7 +477,7 @@ out:
 	return ret;
 }
 
-const struct super_operations exofs_sops = {
+static const struct super_operations exofs_sops = {
 	.alloc_inode    = exofs_alloc_inode,
 	.destroy_inode  = exofs_destroy_inode,
 	.write_inode    = exofs_write_inode,
@@ -488,6 +490,7 @@ const struct super_operations exofs_sops = {
 /******************************************************************************
  * EXPORT OPERATIONS
  *****************************************************************************/
+
 struct dentry *exofs_get_parent(struct dentry *child)
 {
 	unsigned long ino = exofs_parent_ino(child);
@@ -528,7 +531,7 @@ static struct dentry *exofs_fh_to_parent(struct super_block *sb,
 				    exofs_nfs_get_inode);
 }
 
-const struct export_operations exofs_export_ops = {
+static const struct export_operations exofs_export_ops = {
 	.fh_to_dentry = exofs_fh_to_dentry,
 	.fh_to_parent = exofs_fh_to_parent,
 	.get_parent = exofs_get_parent,
#1 lore raw

PATCH 1/9 exofs: Kbuild, Headers and osd utils

This patch includes osd infrastructure that will be used later by the file system.

Also the declarations of constants, on disk structures, and prototypes.

And the Kbuild+Kconfig files needed to build the exofs module.

---
 fs/exofs/Kbuild   |   16 +++++
 fs/exofs/Kconfig  |   13 ++++
 fs/exofs/common.h |  184 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/exofs/exofs.h  |  127 ++++++++++++++++++++++++++++++++++++
 fs/exofs/osd.c    |  153 ++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 493 insertions(+), 0 deletions(-)
 create mode 100644 fs/exofs/Kbuild
 create mode 100644 fs/exofs/Kconfig
 create mode 100644 fs/exofs/common.h
 create mode 100644 fs/exofs/exofs.h
 create mode 100644 fs/exofs/osd.c
fs/exofs/Kbuild new file +16 -0
new file mode 100644
index 0000000..36d23ca
@@ -0,0 +1,16 @@
+#
+# Kbuild for the EXOFS module
+#
+# Copyright (C) 2008 Panasas Inc.  All rights reserved.
+#
+# Authors:
+#   Boaz Harrosh <[email protected]>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2
+#
+# Kbuild - Gets included from the Kernels Makefile and build system
+#
+
+exofs-y := osd.o
+obj-$(CONFIG_EXOFS_FS) += exofs.o
fs/exofs/Kconfig new file +13 -0
new file mode 100644
index 0000000..86194b2
@@ -0,0 +1,13 @@
+config EXOFS_FS
+	tristate "exofs: OSD based file system support"
+	depends on SCSI_OSD_ULD
+	help
+	  EXOFS is a file system that uses an OSD storage device,
+	  as its backing storage.
+
+# Debugging-related stuff
+config EXOFS_DEBUG
+	bool "Enable debugging"
+	depends on EXOFS_FS
+	help
+	  This option enables EXOFS debug prints.
fs/exofs/common.h new file +184 -0

184 lines not on this page · raw message

fs/exofs/exofs.h new file +127 -0

127 lines not on this page · raw message

fs/exofs/osd.c new file +153 -0

153 lines not on this page · raw message

Signature · 1 line
1.6.2.1
#4 lore raw

PATCH 2/9 exofs: file and file_inode operations

In reply to Boaz Harrosh

implementation of the file_operations and inode_operations for regular data files.

Most file_operations are generic vfs implementations except:
- exofs_truncate will truncate the OSD object as well
- Generic file_fsync is not good for none_bd devices so open code it
- The default for .flush in Linux is todo nothing so call exofs_fsync on the file.

---
 fs/exofs/Kbuild  |    2 +-
 fs/exofs/exofs.h |   14 +++++
 fs/exofs/file.c  |   87 ++++++++++++++++++++++++++++++++
 fs/exofs/inode.c |  148 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 250 insertions(+), 1 deletions(-)
 create mode 100644 fs/exofs/file.c
 create mode 100644 fs/exofs/inode.c
fs/exofs/Kbuild +1 -1
index 36d23ca..c9546ed 100644
@@ -12,5 +12,5 @@
 # Kbuild - Gets included from the Kernels Makefile and build system
 #
 
-exofs-y := osd.o
+exofs-y := osd.o inode.o file.o
 obj-$(CONFIG_EXOFS_FS) += exofs.o
fs/exofs/exofs.h +14 -0
index 365376d..a735258 100644
@@ -124,4 +124,18 @@ static inline struct exofs_i_info *exofs_i(struct inode *inode)
 	return container_of(inode, struct exofs_i_info, vfs_inode);
 }
 
+/*************************
+ * function declarations *
+ *************************/
+/* inode.c               */
+void exofs_truncate(struct inode *inode);
+int exofs_setattr(struct dentry *, struct iattr *);
+
+/*********************
+ * operation vectors *
+ *********************/
+/* file.c            */
+extern const struct inode_operations exofs_file_inode_operations;
+extern const struct file_operations exofs_file_operations;
+
 #endif
fs/exofs/file.c new file +87 -0

87 lines not on this page · raw message

fs/exofs/inode.c new file +148 -0

148 lines not on this page · raw message

Signature · 1 line
1.6.2.1
#5 lore raw

PATCH 3/9 exofs: symlink_inode and fast_symlink_inode operations

In reply to Boaz Harrosh

Generic implementation of symlink ops.

---
 fs/exofs/Kbuild    |    2 +-
 fs/exofs/exofs.h   |    4 +++
 fs/exofs/symlink.c |   57 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 62 insertions(+), 1 deletions(-)
 create mode 100644 fs/exofs/symlink.c
fs/exofs/Kbuild +1 -1
index c9546ed..7c361c9 100644
@@ -12,5 +12,5 @@
 # Kbuild - Gets included from the Kernels Makefile and build system
 #
 
-exofs-y := osd.o inode.o file.o
+exofs-y := osd.o inode.o file.o symlink.o
 obj-$(CONFIG_EXOFS_FS) += exofs.o
fs/exofs/exofs.h +4 -0
index a735258..825454d 100644
@@ -138,4 +138,8 @@ int exofs_setattr(struct dentry *, struct iattr *);
 extern const struct inode_operations exofs_file_inode_operations;
 extern const struct file_operations exofs_file_operations;
 
+/* symlink.c         */
+extern const struct inode_operations exofs_symlink_inode_operations;
+extern const struct inode_operations exofs_fast_symlink_inode_operations;
+
 #endif
fs/exofs/symlink.c new file +57 -0

57 lines not on this page · raw message

Signature · 1 line
1.6.2.1
#6 lore raw

PATCH 4/9 exofs: address_space_operations

In reply to Boaz Harrosh

OK Now we start to read and write from osd-objects. We try to collect at most contiguous pages as possible in a single write/read. The first page index is the object's offset.

TODO:
In 64-bit a single bio can carry at most 128 pages. Add support of chaining multiple bios

---
 fs/exofs/exofs.h |    6 +
 fs/exofs/inode.c |  697 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 703 insertions(+), 0 deletions(-)
fs/exofs/exofs.h +6 -0
index 825454d..0276242 100644
@@ -130,6 +130,9 @@ static inline struct exofs_i_info *exofs_i(struct inode *inode)
 /* inode.c               */
 void exofs_truncate(struct inode *inode);
 int exofs_setattr(struct dentry *, struct iattr *);
+int exofs_write_begin(struct file *file, struct address_space *mapping,
+		loff_t pos, unsigned len, unsigned flags,
+		struct page **pagep, void **fsdata);
 
 /*********************
  * operation vectors *
@@ -138,6 +141,9 @@ int exofs_setattr(struct dentry *, struct iattr *);
 extern const struct inode_operations exofs_file_inode_operations;
 extern const struct file_operations exofs_file_operations;
 
+/* inode.c           */
+extern const struct address_space_operations exofs_aops;
+
 /* symlink.c         */
 extern const struct inode_operations exofs_symlink_inode_operations;
 extern const struct inode_operations exofs_fast_symlink_inode_operations;
fs/exofs/inode.c +697 -0

709 lines not on this page · raw message

Signature · 1 line
1.6.2.1
#7 lore raw

PATCH 5/9 exofs: dir_inode and directory operations

In reply to Boaz Harrosh

implementation of directory and inode operations.

* A directory is treated as a file, and essentially contains a list of <file name, inode #> pairs for files that are found in that directory. The object IDs correspond to the files' inode numbers and are allocated using a 64bit incrementing global counter.
* Each file's control block (AKA on-disk inode) is stored in its object's attributes. This applies to both regular files and other types (directories, device files, symlinks, etc.).

---
 fs/exofs/Kbuild  |    2 +-
 fs/exofs/dir.c   |  657 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/exofs/exofs.h |   26 +++
 fs/exofs/inode.c |  272 ++++++++++++++++++++++
 fs/exofs/namei.c |  342 ++++++++++++++++++++++++++++
 5 files changed, 1298 insertions(+), 1 deletions(-)
 create mode 100644 fs/exofs/dir.c
 create mode 100644 fs/exofs/namei.c
fs/exofs/Kbuild +1 -1
index 7c361c9..0a23f24 100644
@@ -12,5 +12,5 @@
 # Kbuild - Gets included from the Kernels Makefile and build system
 #
 
-exofs-y := osd.o inode.o file.o symlink.o
+exofs-y := osd.o inode.o file.o symlink.o namei.o dir.o
 obj-$(CONFIG_EXOFS_FS) += exofs.o
fs/exofs/dir.c new file +657 -0

657 lines not on this page · raw message

fs/exofs/exofs.h +26 -0
index 0276242..d11982c 100644
@@ -124,6 +124,11 @@ static inline struct exofs_i_info *exofs_i(struct inode *inode)
 	return container_of(inode, struct exofs_i_info, vfs_inode);
 }
 
+/*
+ * Maximum count of links to a file
+ */
+#define EXOFS_LINK_MAX           32000
+
 /*************************
  * function declarations *
  *************************/
@@ -133,10 +138,27 @@ int exofs_setattr(struct dentry *, struct iattr *);
 int exofs_write_begin(struct file *file, struct address_space *mapping,
 		loff_t pos, unsigned len, unsigned flags,
 		struct page **pagep, void **fsdata);
+extern struct inode *exofs_iget(struct super_block *, unsigned long);
+struct inode *exofs_new_inode(struct inode *, int);
+
+/* dir.c:                */
+int exofs_add_link(struct dentry *, struct inode *);
+ino_t exofs_inode_by_name(struct inode *, struct dentry *);
+int exofs_delete_entry(struct exofs_dir_entry *, struct page *);
+int exofs_make_empty(struct inode *, struct inode *);
+struct exofs_dir_entry *exofs_find_entry(struct inode *, struct dentry *,
+					 struct page **);
+int exofs_empty_dir(struct inode *);
+struct exofs_dir_entry *exofs_dotdot(struct inode *, struct page **);
+int exofs_set_link(struct inode *, struct exofs_dir_entry *, struct page *,
+		    struct inode *);
 
 /*********************
  * operation vectors *
  *********************/
+/* dir.c:            */
+extern const struct file_operations exofs_dir_operations;
+
 /* file.c            */
 extern const struct inode_operations exofs_file_inode_operations;
 extern const struct file_operations exofs_file_operations;
@@ -144,6 +166,10 @@ extern const struct file_operations exofs_file_operations;
 /* inode.c           */
 extern const struct address_space_operations exofs_aops;
 
+/* namei.c           */
+extern const struct inode_operations exofs_dir_inode_operations;
+extern const struct inode_operations exofs_special_inode_operations;
+
 /* symlink.c         */
 extern const struct inode_operations exofs_symlink_inode_operations;
 extern const struct inode_operations exofs_fast_symlink_inode_operations;
fs/exofs/inode.c +272 -0

275 lines not on this page · raw message

fs/exofs/namei.c new file +342 -0

342 lines not on this page · raw message

Signature · 1 line
1.6.2.1
#8 lore raw

PATCH 6/9 exofs: super_operations and file_system_type

In reply to Boaz Harrosh

This patch ties all operation vectors into a file system superblock and registers the exofs file_system_type at module's load time.

* The file system control block (AKA on-disk superblock) resides in an object with a special ID (defined in common.h). Information included in the file system control block is used to fill the in-memory superblock structure at mount time. This object is created before the file system is used by mkexofs.c It contains information such as:
- The file system's magic number
- The next inode number to be allocated

---
 fs/exofs/Kbuild  |    2 +-
 fs/exofs/exofs.h |    2 +
 fs/exofs/inode.c |  186 +++++++++++++++++++
 fs/exofs/super.c |  531 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 720 insertions(+), 1 deletions(-)
 create mode 100644 fs/exofs/super.c
fs/exofs/Kbuild +1 -1
index 0a23f24..cc2d22d 100644
@@ -12,5 +12,5 @@
 # Kbuild - Gets included from the Kernels Makefile and build system
 #
 
-exofs-y := osd.o inode.o file.o symlink.o namei.o dir.o
+exofs-y := osd.o inode.o file.o symlink.o namei.o dir.o super.o
 obj-$(CONFIG_EXOFS_FS) += exofs.o
fs/exofs/exofs.h +2 -0
index d11982c..11e11d5 100644
@@ -140,6 +140,8 @@ int exofs_write_begin(struct file *file, struct address_space *mapping,
 		struct page **pagep, void **fsdata);
 extern struct inode *exofs_iget(struct super_block *, unsigned long);
 struct inode *exofs_new_inode(struct inode *, int);
+extern int exofs_write_inode(struct inode *, int);
+extern void exofs_delete_inode(struct inode *);
 
 /* dir.c:                */
 int exofs_add_link(struct dentry *, struct inode *);
fs/exofs/inode.c +186 -0

189 lines not on this page · raw message

fs/exofs/super.c new file +531 -0

531 lines not on this page · raw message

Signature · 1 line
1.6.2.1
#9 lore raw

PATCH 7/9 exofs: export_operations

In reply to Boaz Harrosh

implement export_operations and set in superblock. It is now posible to export exofs via nfs

---
 fs/exofs/dir.c   |   15 +++++++++++++++
 fs/exofs/exofs.h |    1 +
 fs/exofs/super.c |   53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 69 insertions(+), 0 deletions(-)
fs/exofs/dir.c +15 -0
index 6865605..65b0c8c 100644
@@ -381,6 +381,21 @@ struct exofs_dir_entry *exofs_dotdot(struct inode *dir, struct page **p)
 	return de;
 }
 
+ino_t exofs_parent_ino(struct dentry *child)
+{
+	struct page *page;
+	struct exofs_dir_entry *de;
+	ino_t ino;
+
+	de = exofs_dotdot(child->d_inode, &page);
+	if (!de)
+		return 0;
+
+	ino = le64_to_cpu(de->inode_no);
+	exofs_put_page(page);
+	return ino;
+}
+
 ino_t exofs_inode_by_name(struct inode *dir, struct dentry *dentry)
 {
 	ino_t res = 0;
fs/exofs/exofs.h +1 -0
index 11e11d5..0fd4c78 100644
@@ -152,6 +152,7 @@ struct exofs_dir_entry *exofs_find_entry(struct inode *, struct dentry *,
 					 struct page **);
 int exofs_empty_dir(struct inode *);
 struct exofs_dir_entry *exofs_dotdot(struct inode *, struct page **);
+ino_t exofs_parent_ino(struct dentry *child);
 int exofs_set_link(struct inode *, struct exofs_dir_entry *, struct page *,
 		    struct inode *);
 
fs/exofs/super.c +53 -0

77 lines not on this page · raw message

Signature · 1 line
1.6.2.1
#10 lore raw

PATCH 8/9 exofs: Documentation

In reply to Boaz Harrosh

Added some documentation in exofs.txt, as well as a BUGS file.

For further reading, operation instructions, example scripts and up to date infomation and code please see:
http://open-osd.org

---
 Documentation/filesystems/exofs.txt |  176 +++++++++++++++++++++++++++++++++++
 fs/exofs/BUGS                       |    3 +
 2 files changed, 179 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/filesystems/exofs.txt
 create mode 100644 fs/exofs/BUGS
Documentation/filesystems/exofs.txt new file +176 -0
new file mode 100644
index 0000000..0ced74c
@@ -0,0 +1,176 @@
+===============================================================================
+WHAT IS EXOFS?
+===============================================================================
+
+exofs is a file system that uses an OSD and exports the API of a normal Linux
+file system. Users access exofs like any other local file system, and exofs
+will in turn issue commands to the local OSD initiator.
+
+OSD is a new T10 command set that views storage devices not as a large/flat
+array of sectors but as a container of objects, each having a length, quota,
+time attributes and more. Each object is addressed by a 64bit ID, and is
+contained in a 64bit ID partition. Each object has associated attributes
+attached to it, which are integral part of the object and provide metadata about
+the object. The standard defines some common obligatory attributes, but user
+attributes can be added as needed.
+
+===============================================================================
+ENVIRONMENT
+===============================================================================
+
+To use this file system, you need to have an object store to run it on.  You
+may download a target from:
+http://open-osd.org
+
+See Documentation/scsi/osd.txt for how to setup a working osd environment.
+
+===============================================================================
+USAGE
+===============================================================================
+
+1. Download and compile exofs and open-osd initiator:
+  You need an external Kernel source tree or kernel headers from your
+  distribution. (anything based on 2.6.26 or later).
+
+  a. download open-osd including exofs source using:
+     [parent-directory]$ git clone git://git.open-osd.org/open-osd.git
+
+  b. Build the library module like this:
+     [parent-directory]$ make -C KSRC=$(KER_DIR) open-osd
+
+     This will build both the open-osd initiator as well as the exofs kernel
+     module. Use whatever parameters you compiled your Kernel with and
+     $(KER_DIR) above pointing to the Kernel you compile against. See the file
+     open-osd/top-level-Makefile for an example.
+
+2. Get the OSD initiator and target set up properly, and login to the target.
+  See Documentation/scsi/osd.txt for farther instructions. Also see ./do-osd
+  for example script that does all these steps.
+
+3. Insmod the exofs.ko module:
+   [exofs]$ insmod exofs.ko
+
+4. Make sure the directory where you want to mount exists. If not, create it.
+   (For example, mkdir /mnt/exofs)
+
+5. At first run you will need to invoke the mkfs.exofs application
+
+   As an example, this will create the file system on:
+   /dev/osd0 partition ID 65536
+
+   mkfs.exofs --pid=65536 --format /dev/osd0
+
+   The --format is optional if not specified no OSD_FORMAT will be
+   preformed and a clean file system will be created in the specified pid,
+   in the available space of the target. (Use --format=size_in_meg to limit
+   the total LUN space available)
+
+   If pid already exist it will be deleted and a new one will be created in it's
+   place. Be careful.
+
+   An exofs lives inside a single OSD partition. You can create multiple exofs
+   filesystems on the same device using multiple pids.
+
+   (run mkfs.exofs without any parameters for usage help message)
+
+6. Mount the file system.
+
+   For example, to mount /dev/osd0, partition ID 0x10000 on /mnt/exofs:
+
+	mount -t exofs -o pid=65536 /dev/osd0 /mnt/exofs/
+
+7. For reference (See do-exofs example script):
+	do-exofs start - an example of how to perform the above steps.
+	do-exofs stop -  an example of how to unmount the file system.
+	do-exofs format - an example of how to format and mkfs a new exofs.
+
+8. Extra compilation flags (uncomment in fs/exofs/Kbuild):
+	CONFIG_EXOFS_DEBUG - for debug messages and extra checks.
+
+===============================================================================
+exofs mount options
+===============================================================================
+Similar to any mount command:
+	mount -t exofs -o exofs_options /dev/osdX mount_exofs_directory
+
+Where:
+    -t exofs: specifies the exofs file system
+
+    /dev/osdX: X is a decimal number. /dev/osdX was created after a successful
+               login into an OSD target.
+
+    mount_exofs_directory: The directory to mount the file system on
+
+    exofs specific options: Options are separated by commas (,)
+		pid=<integer> - The partition number to mount/create as
+                                container of the filesystem.
+                                This option is mandatory
+                to=<integer>  - Timeout in ticks for a single command
+                                default is (60 * HZ) [for debugging only]
+
+===============================================================================
+DESIGN
+===============================================================================
+
+* The file system control block (AKA on-disk superblock) resides in an object
+  with a special ID (defined in common.h).
+  Information included in the file system control block is used to fill the
+  in-memory superblock structure at mount time. This object is created before
+  the file system is used by mkexofs.c It contains information such as:
+	- The file system's magic number
+	- The next inode number to be allocated
+
+* Each file resides in its own object and contains the data (and it will be
+  possible to extend the file over multiple objects, though this has not been
+  implemented yet).
+
+* A directory is treated as a file, and essentially contains a list of <file
+  name, inode #> pairs for files that are found in that directory. The object
+  IDs correspond to the files' inode numbers and will be allocated according to
+  a bitmap (stored in a separate object). Now they are allocated using a
+  counter.
+
+* Each file's control block (AKA on-disk inode) is stored in its object's
+  attributes. This applies to both regular files and other types (directories,
+  device files, symlinks, etc.).
+
+* Credentials are generated per object (inode and superblock) when they is
+  created in memory (read off disk or created). The credential works for all
+  operations and is used as long as the object remains in memory.
+
+* Async OSD operations are used whenever possible, but the target may execute
+  them out of order. The operations that concern us are create, delete,
+  readpage, writepage, update_inode, and truncate. The following pairs of
+  operations should execute in the order written, and we need to prevent them
+  from executing in reverse order:
+	- The following are handled with the OBJ_CREATED and OBJ_2BCREATED
+	  flags. OBJ_CREATED is set when we know the object exists on the OSD -
+	  in create's callback function, and when we successfully do a read_inode.
+	  OBJ_2BCREATED is set in the beginning of the create function, so we
+	  know that we should wait.
+		- create/delete: delete should wait until the object is created
+		  on the OSD.
+		- create/readpage: readpage should be able to return a page
+		  full of zeroes in this case. If there was a write already
+		  en-route (i.e. create, writepage, readpage) then the page
+		  would be locked, and so it would really be the same as
+		  create/writepage.
+		- create/writepage: if writepage is called for a sync write, it
+		  should wait until the object is created on the OSD.
+		  Otherwise, it should just return.
+		- create/truncate: truncate should wait until the object is
+		  created on the OSD.
+		- create/update_inode: update_inode should wait until the
+		  object is created on the OSD.
+	- Handled by VFS locks:
+		- readpage/delete: shouldn't happen because of page lock.
+		- writepage/delete: shouldn't happen because of page lock.
+		- readpage/writepage: shouldn't happen because of page lock.
+
+===============================================================================
+LICENSE/COPYRIGHT
+===============================================================================
+The exofs file system is based on ext2 v0.5b (distributed with the Linux kernel
+version 2.6.10).  All files include the original copyrights, and the license
+is GPL version 2 (only version 2, as is true for the Linux kernel).  The
+Linux kernel can be downloaded from www.kernel.org.
fs/exofs/BUGS new file +3 -0
new file mode 100644
index 0000000..1b2d4c6
@@ -0,0 +1,3 @@
+- Out-of-space may cause a severe problem if the object (and directory entry)
+  were written, but the inode attributes failed. Then if the filesystem was
+  unmounted and mounted the kernel can get into an endless loop doing a readdir.
Signature · 1 line
1.6.2.1
#11 lore raw

PATCH 9/9 fs: Add exofs to Kernel build

In reply to Boaz Harrosh

- Add exofs to fs/Kconfig under "menu 'Miscellaneous filesystems'"
- Add exofs to fs/Makefile

---
 fs/Kconfig  |    2 ++
 fs/Makefile |    1 +
 2 files changed, 3 insertions(+), 0 deletions(-)
fs/Kconfig +2 -0
index cef8b18..ae3b34a 100644
@@ -169,6 +169,8 @@ source "fs/romfs/Kconfig"
 source "fs/sysv/Kconfig"
 source "fs/ufs/Kconfig"
 
+source "fs/exofs/Kconfig"
+
 endif # MISC_FILESYSTEMS
 
 menuconfig NETWORK_FILESYSTEMS
fs/Makefile +1 -0
index 6e82a30..ba77ef2 100644
@@ -120,3 +120,4 @@ obj-$(CONFIG_DEBUG_FS)		+= debugfs/
 obj-$(CONFIG_OCFS2_FS)		+= ocfs2/
 obj-$(CONFIG_BTRFS_FS)		+= btrfs/
 obj-$(CONFIG_GFS2_FS)           += gfs2/
+obj-$(CONFIG_EXOFS_FS)          += exofs/
Signature · 1 line
1.6.2.1
#2 lore raw

Re: [PATCH 1/9] exofs: Kbuild, Headers and osd utils

In reply to Boaz Harrosh
Quoted 9 lines · Boaz Harrosh

This patch includes osd infrastructure that will be used later by the file system.

Also the declarations of constants, on disk structures, and prototypes.

And the Kbuild+Kconfig files needed to build the exofs module.

Quoted 12 lines
---
 fs/exofs/Kbuild   |   16 +++++
 fs/exofs/Kconfig  |   13 ++++
 fs/exofs/common.h |  184 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/exofs/exofs.h  |  127 ++++++++++++++++++++++++++++++++++++
 fs/exofs/osd.c    |  153 ++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 493 insertions(+), 0 deletions(-)
 create mode 100644 fs/exofs/Kbuild
 create mode 100644 fs/exofs/Kconfig
 create mode 100644 fs/exofs/common.h
 create mode 100644 fs/exofs/exofs.h
 create mode 100644 fs/exofs/osd.c

After building "osdblk", a block driver using libosd, it is my opinion that all functions inside fs/exofs/osd.c should be moved to libosd.

I find myself copying most of that file, to use in osdblk.

Jeff

#3 lore raw

Re: [PATCH 1/9] exofs: Kbuild, Headers and osd utils

Quoted 23 lines · Jeff Garzik
Quoted 9 lines · Boaz Harrosh

This patch includes osd infrastructure that will be used later by the file system.

Also the declarations of constants, on disk structures, and prototypes.

And the Kbuild+Kconfig files needed to build the exofs module.

Quoted 12 lines
---
 fs/exofs/Kbuild   |   16 +++++
 fs/exofs/Kconfig  |   13 ++++
 fs/exofs/common.h |  184 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/exofs/exofs.h  |  127 ++++++++++++++++++++++++++++++++++++
 fs/exofs/osd.c    |  153 ++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 493 insertions(+), 0 deletions(-)
 create mode 100644 fs/exofs/Kbuild
 create mode 100644 fs/exofs/Kconfig
 create mode 100644 fs/exofs/common.h
 create mode 100644 fs/exofs/exofs.h
 create mode 100644 fs/exofs/osd.c
Quoted 7 lines

After building "osdblk", a block driver using libosd, it is my opinion that all functions inside fs/exofs/osd.c should be moved to libosd.

I find myself copying most of that file, to use in osdblk.

Jeff

Yes I agree

I have such patches queued on my oo-devel branch that remove half, and a plan to remove the second half in a more generic manner.

The problem with those left is that they set policy like the parameters in the call to osd_finalize_request, but it might be better to just fold these into osd_execute_*

My long time plan was to implement at first the lowest level only, then over time when repeated recipes arise add them. I guess "later" as arrived.

Thanks
Boaz