linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH] CMS minidisk filesystem support
@ 2008-09-22  1:29 Josef 'Jeff' Sipek
  2008-09-22  1:29 ` [PATCH 01/12] cmsfs: Documentation Josef 'Jeff' Sipek
                   ` (11 more replies)
  0 siblings, 12 replies; 13+ messages in thread
From: Josef 'Jeff' Sipek @ 2008-09-22  1:29 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: hch

Hello all!

here are patches to add support for reading CMS EDF filesystems.  CMS is a
single user operating system that is part of IBM's z/VM.  Even the tiniest
of z/VM installations will have a bunch of minidisks formated with this
filesystem.  Think of it as the VFAT of s390 (in terms of popularity).

These patches are loosly based on cmsfs from 2.4.12-ac6.

NOTE:
I decided to send out these patches now even though they're not complete at
the moment.  I plan to expand this description, expand the documentation,
and bunch of other things.

TODO list at the moment:
 - file data translation (EBCDIC to ASCII)
 - support for RECFM=V files
 - better documentation
 - cleanup the code
 - ...and whatever else comes up

Josef 'Jeff' Sipek.
jeffpc@josefsipek.net

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 01/12] cmsfs: Documentation
  2008-09-22  1:29 [RFC PATCH] CMS minidisk filesystem support Josef 'Jeff' Sipek
@ 2008-09-22  1:29 ` Josef 'Jeff' Sipek
  2008-09-22  1:29 ` [PATCH 02/12] cmsfs: header file Josef 'Jeff' Sipek
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Josef 'Jeff' Sipek @ 2008-09-22  1:29 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: hch, Josef 'Jeff' Sipek

Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
---
 Documentation/filesystems/cmsfs.txt |   64 +++++++++++++++++++++++++++++++++++
 1 files changed, 64 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/filesystems/cmsfs.txt

diff --git a/Documentation/filesystems/cmsfs.txt b/Documentation/filesystems/cmsfs.txt
new file mode 100644
index 0000000..d4bcf96
--- /dev/null
+++ b/Documentation/filesystems/cmsfs.txt
@@ -0,0 +1,64 @@
+CMS Minidisk Filesystem
+=======================
+
+<FIXME: high-level description of CMSFS>
+
+
+Mount options
+=============
+
+(none)
+
+
+Extended attributes
+===================
+
+While the filesystem itself doesn't support extended attributes, the xattr
+interface can be used to extract additional information about each file.
+
+    system.items:    number of records in this file
+    system.lrecl:    record length
+    system.recfm:    record format
+
+
+Specification
+=============
+
+<FIXME: detailed description of the on-disk structures>
+
+
+Credits
+=======
+
+This implementation has been loosly based on a cmsfs patch from 2.4.12-ac6
+by Rick Troth <rtroth@bmc.com>.
+
+CMS minidisk (EDF) filesystem specifications taken from
+http://www.vm.ibm.com/pubs/cmsdacb/FSTD.HTML,
+http://www.vm.ibm.com/pubs/cmsdacb/ADTSECT.HTML,
+and the Linux kernel patches supplied by IBM (mdisk driver).
+
+
+Credits from the 2.4.12-ac6 patch
+=================================
+
+Thanks to Dave Hilbe for supporting this project.
+
+Thanks to Arty Ecock <ECKCU@CUNYVM.CUNY.EDU> for pointing me
+back at ADT after I had misunderstood it in my first look.
+
+Thanks to Rob van der Heij for help with the logic.
+
+Thanks to Neale Ferguson for "cpint".
+
+Thanks to Willem Konynenberg <wfk@xos.nl>
+for moral support and championing correct DASD I/O.
+
+Thanks to Alan Cox for help figuring out Linux VFS.
+
+Thanks to Reed Mullen for clarifying permission to use doc.
+
+Thanks to Marilyn Troth for advice about packaging,  helping
+me stay focused,  and for putting up with all the late nights.
+
+... and many others whom I am sorry to have omitted.
-- 
1.5.6.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 02/12] cmsfs: header file
  2008-09-22  1:29 [RFC PATCH] CMS minidisk filesystem support Josef 'Jeff' Sipek
  2008-09-22  1:29 ` [PATCH 01/12] cmsfs: Documentation Josef 'Jeff' Sipek
@ 2008-09-22  1:29 ` Josef 'Jeff' Sipek
  2008-09-22  1:29 ` [PATCH 03/12] cmsfs: EBCDIC translation table Josef 'Jeff' Sipek
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Josef 'Jeff' Sipek @ 2008-09-22  1:29 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: hch, Josef 'Jeff' Sipek

Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
---
 fs/cmsfs/cmsfs.h      |  260 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/magic.h |    1 +
 2 files changed, 261 insertions(+), 0 deletions(-)
 create mode 100644 fs/cmsfs/cmsfs.h

diff --git a/fs/cmsfs/cmsfs.h b/fs/cmsfs/cmsfs.h
new file mode 100644
index 0000000..ab69e32
--- /dev/null
+++ b/fs/cmsfs/cmsfs.h
@@ -0,0 +1,260 @@
+#ifndef _CMSFS_H
+#define _CMSFS_H
+/*
+ * CMSFS
+ *
+ *  (C) 2008  Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
+ *
+ * Based on cmsfs from 2.4.12-ac6:
+ *
+ *  (C) 2001  Rick Troth <rtroth@bmc.com>
+ *  (C) 2001  BMC Software, Inc., Houston, Texas, USA
+ *
+ */
+
+/******************/
+/* FIXME: remove */
+extern __u8 _ascebc[256];   /* ASCII -> EBCDIC conversion table */
+extern __u8 _ebcasc[256];   /* EBCDIC -> ASCII conversion table */
+
+static inline void ebc_trans(__u8 *table, __u8 *addr, int len)
+{
+	for(; len; len--)
+		addr[len-1] = table[addr[len-1]];
+}
+
+#define EBC2ASC(addr,len) ebc_trans(_ebcasc, (addr), (len))
+#define ASC2EBC(addr,len) ebc_trans(_ascebc, (addr), (len))
+/******************/
+
+#define	CMSFS_FIRST_INO		8
+#define	CMSFS_DIRECTOR_INO	CMSFS_FIRST_INO
+#define	CMSFS_ALLOCMAP_INO	(CMSFS_DIRECTOR_INO + 1)
+
+/* filename (up to 8) + period + filetype (up to 8) */
+#define CMSFS_NAME_LEN		17
+
+/* Record format */
+enum recfm {
+	RECFM_FIXED = 0xc6, /* EBCDIC 'F' */
+	RECFM_VAR   = 0xe5, /* EBCDIC 'V' */
+};
+
+/*
+ * private data structs
+ */
+struct cmsfs_inode_info {
+	struct inode	vfs_inode;    /* Linux VFS inode */
+
+	enum recfm	recfm;
+	u32		lrecl;
+	u32		origin;       /* "base one" File Origin Pointer (FOP) */
+				      /* "base zero" offset is derived from FOP */
+	u32		blocks;       /* blocks in first-level */
+				      /* If there is only one level, then
+				         this is the total number of blocks */
+	u32		items;        /* number of records in this file */
+	u32		level;        /* level of indirection */
+	u32		psize;        /* size of indir pointers */
+
+	time_t		ctime;        /* computed UNIX time from CMS timestamp */
+};
+
+struct cmsfs_sb_info {
+	char    volid[7];       /* volume label (volume serial number) */
+	long	blksz;          /* statfs f_bsize block size of this volume */
+	int     origin;         /* "base one" Directory Origin Pointer (DOP) */
+	                        /* "base zero" offset is derived from DOP */
+	int     ncyls;          /* number of cylinders used by filesystem */
+	int     mcyls;          /* number of cylinders on the disk */
+				/* CMS has a concept of "recomp" where
+				   cylinders beyond the filesystem may be
+				   used by other things, like a boot loader. */
+	long	blocks;         /* statfs f_blocks: total number of blocks
+				   in the filesystem */
+	long    bkused;		/* blocks used (per ADT) */
+	int     fstsz;          /* size of each directory entry (of each FST) */
+	int     fstct;          /* number of FSTs (FST count) per block */
+	time_t  ctime;          /* time when this filesystem was created */
+	int     resoff;         /* reserved offset */
+	                        /* CMS has a concept of a "reserved disk"
+	                           where one file occupies the entire disk.
+	                           Additionally,  that file is referenced by this
+	                           so that the filesystem (directory) mechanism
+	                           can be bypassed. */
+	long    files;          /* statfs f_files: extracted from directory
+				   FST "items" */
+};
+
+/*
+ * Function prototypes
+ */
+extern int cmsfs_read_block(struct super_block *sb, void *buf, int block,
+			    unsigned blocksize);
+extern struct inode *cmsfs_iget(struct super_block *sb, unsigned long ino);
+extern void munge_name(__u8 *name, char *outname);
+extern ssize_t cmsfs_getxattr(struct dentry *dentry, const char *name,
+			      void *value, size_t size);
+extern int cmsfs_setxattr(struct dentry *dentry, const char *name,
+			  const void *value, size_t size, int flags);
+extern int cmsfs_removexattr(struct dentry *dentry, const char *name);
+extern ssize_t cmsfs_listxattr(struct dentry *dentry, char *list, size_t size);
+
+/*
+ * Static inlines
+ */
+static inline struct cmsfs_sb_info *CMSFS_SB(struct super_block *sb)
+{
+	return sb->s_fs_info;
+}
+
+static inline struct cmsfs_inode_info *CMSFS_I(struct inode *inode)
+{
+	return container_of(inode, struct cmsfs_inode_info, vfs_inode);
+}
+
+static inline int hex2int(__u8 c)
+{
+	return ((c >> 4) * 10) + (c & 0xf);
+}
+
+extern struct file_operations cmsfs_file_ops;
+extern struct address_space_operations cmsfs_aops;
+
+/*
+ * On disk structures
+ */
+
+/*
+ * File Status Table (FST)
+ *
+ * This information is based on VM/ESA 2.4.0.
+ * Last updated on 12 Aug 1999 at 11:21:05 EDT.
+ * Copyright IBM Corporation, 1990, 1999
+ * http://www.vm.ibm.com/pubs/cmsdacb/FSTD.HTML
+ *
+ *
+ *     +-------------------------------------------------------+
+ *   0 |                       FSTFNAME                        |
+ *     +-------------------------------------------------------+
+ *   8 |                       FSTFTYPE                        |
+ *     +-------------+-------------+-------------+-------------+
+ *  10 |  FSTDATEW   |  FSTTIMEW   |  FSTWRPNT   |  FSTRDPNT   |
+ *     +-------------+-------------+-------------+------+------+
+ *  18 |  FSTFMODE   |  FSTRECCT   |  FSTFCLPT   |:RECFM|:FLAGS|
+ *     +-------------+-------------+-------------+------+------+
+ *  20 |         FSTLRECL          |  FSTBLKCT   |  FSTYEARW   |
+ *     +---------------------------+-------------+-------------+
+ *  28 |          FSTFOP           |         FSTADBC           |
+ *     +---------------------------+------+------+-------------+
+ *  30 |          FSTAIC           |:NLVL |:PTRSZ|   (036)-    |
+ *     +---------------------------+------+------+-------------+
+ *  38 |        -FSTADATI          |:REALM|:FLAG2|/////////////|
+ *     +---------------------------+------+------+-------------+
+ *  40
+ *
+ */
+struct CMSFSFST {
+	__u8    FSTFNAME[8];       /* filename */
+	__u8    FSTFTYPE[8];       /* filetype */
+	__u8    FSTDATEW[2];       /* DATE LAST WRITTEN - MMDD */
+	__u8    FSTTIMEW[2];       /* TIME LAST WRITTEN - HHMM */
+	__be16  FSTWRPNT;          /* WRITE POINTER - ITEM NUMBER */
+	__be16  FSTRDPNT;          /* READ POINTER - ITEM NUMBER */
+	__u8    FSTFMODE[2];       /* FILE MODE - LETTER AND NUMBER */
+	__be16  FSTRECCT;          /* NUMBER OF LOGICAL RECORDS */
+	__be16  FSTFCLPT;          /* FIRST CHAIN LINK POINTER */
+	__u8    FSTRECFM;          /* F*1 - RECORD FORMAT - F OR V */
+#define FSTDFIX        0xC6 /* Fixed record format (EBCDIC 'F') */
+#define FSTDVAR        0xE5 /* Variable record format (EBCDIC 'V') */
+	__u8    FSTFLAGS;          /* F*2 - FST FLAG BYTE */
+#define FSTRWDSK       0x80 /* READ/WRITE DISK */
+#define FSTRODSK       0x00 /* READ/ONLY DISK */
+#define FSTDSFS        0x10 /* Shared File FST */
+#define FSTXRDSK       0x40 /* EXTENSION OF R/O DISK */
+#define FSTXWDSK       0xC0 /* EXTENSION OF R/W DISK */
+#define FSTEPL         0x20 /* EXTENDED PLIST */
+#define FSTDIA         0x40 /* ITEM AVAILABLE */
+#define FSTDRA         0x01 /* PREVIOUS RECORD NULL */
+#define FSTCNTRY       0x08 /* Century for date last written (0=19, 1=20),\\
+			       corresponds to FSTYEARW, FSTADATI. */
+#define FSTACTRD       0x04 /* ACTIVE FOR READING */
+#define FSTACTWR       0x02 /* ACTIVE FOR WRITING */
+#define FSTACTPT       0x01 /* ACTIVE FROM A POINT */
+#define FSTFILEA       0x07 /* THE FILE IS ACTIVE */
+	__be32  FSTLRECL;          /* LOGICAL RECORD LENGTH */
+	__be16  FSTBLKCT;          /* NUMBER OF 800 BYTE BLOCKS */
+	__be16  FSTYEARW;          /* YEAR LAST WRITTEN */
+	__be32  FSTFOP;            /* ALT. FILE ORIGIN POINTER */
+	__be32  FSTADBC;           /* ALT. NUMBER OF DATA BLOCKS */
+	__be32  FSTAIC;            /* ALT. ITEM COUNT */
+	__u8    FSTNLVL;           /* NUMBER OF POINTER BLOCK LEVELS */
+	__u8    FSTPTRSZ;          /* LENGTH OF A POINTER ELEMENT */
+	__u8    FSTADATI[6];       /* ALT. DATE/TIME(YY MM DD HH MM SS) */
+	__u8    FSTREALM;          /* Real filemode */
+	__u8    FSTFLAG2;          /* F*3 - FST FLAG BYTE 2 FSTFLAG2 */
+#define FSTPIPEU       0x10 /* Reserved for CMS PIPELINES usage */
+	__u8    reserved[2];
+};
+
+/*
+ * Active Disk Table (ADT) volume label
+ *
+ * This information is based on VM/ESA 2.4.0.
+ * Last updated on 12 Aug 1999 at 11:17:01 EDT.
+ * Copyright IBM Corporation, 1990, 1999
+ * http://www.vm.ibm.com/pubs/cmsdacb/ADTSECT.HTML
+ *
+ *
+ * The volume portion of ADT beings at offset 0x90 into the actual ADT
+ *
+ *     +---------------------------+---------------------------+
+ *  90 |         ADTIDENT          |          ADTID-           |
+ *     +-------------+-------------+---------------------------+
+ *  98 |   -(094)    |   ADTVER    |         ADTDBSIZ          |
+ *     +-------------+-------------+---------------------------+
+ *  A0 |          ADTDOP           |          ADTCYL           |
+ *     +---------------------------+---------------------------+
+ *  A8 |         ADTMCYL           |          ADTNUM           |
+ *     +---------------------------+---------------------------+
+ *  B0 |         ADTUSED           |         ADTFSTSZ          |
+ *     +---------------------------+---------------------------+
+ *  B8 |         ADTNFST           |        ADTDCRED-          |
+ *     +-------------+------+------+---------------------------+
+ *  C0 |   -(0BC)    |:FLGL |//////|         ADTOFFST          |
+ *     +-------------+------+------+---------------------------+
+ *  C8 |         ADTAMNB           |         ADTAMND           |
+ *     +---------------------------+---------------------------+
+ *  D0 |         ADTAMUP           |         ADTOFCNT          |
+ *     +---------------------------+---------------------------+
+ *  D8 |                       ADTSFNAM                        |
+ *     +-------------------------------------------------------+
+ *  E0
+ *
+ */
+struct CMSFSADT {
+	__be32  ADTIDENT;       /* VOL START / LABEL IDENTIFIER */
+	__u8    ADTID[6];       /* VOL START / VOL IDENTIFIER */
+	__u8    ADTVER[2];      /* VERSION LEVEL */
+	__be32  ADTDBSIZ;       /* DISK BLOCK SIZE */
+	__be32  ADTDOP;         /* DISK ORIGIN POINTER */
+	__be32  ADTCYL;         /* NUM OF FORMATTED CYL ON DISK */
+	__be32  ADTMCYL;        /* MAX NUM FORMATTED CYL ON DISK */
+	__be32  ADTNUM;         /* Number of Blocks on disk */
+	__be32  ADTUSED;        /* Number of Blocks used */
+	__be32  ADTFSTSZ;       /* SIZE OF FST */
+	__be32  ADTNFST;        /* NUMBER OF FST'S PER BLOCK */
+	__u8    ADTDCRED[6];    /* DISK CREATION DATE (YYMMDDHHMMSS) */
+	__u8    ADTFLGL;        /* LABEL FLAG BYTE (ADTFLGL) */
+#define ADTCNTRY        0x01 /* Century for disk creation date (0=19, 1=20),\\
+			      * corresponds to ADTDCRED. */
+	__u8    reserved[1];
+	__be32  ADTOFFST;       /* DISK OFFSET WHEN RESERVED */
+	__be32  ADTAMNB;        /* ALLOC MAP BLOCK WITH NEXT HOLE */
+	__be32  ADTAMND;        /* DISP INTO HBLK DATA OF NEXT HOLE */
+	__be32  ADTAMUP;        /* DISP INTO USER PART OF ALLOC MAP */
+	__be32  ADTOFCNT;       /* Count of SFS open files for this ADT */
+	__u8    ADTSFNAM[8];    /* NAME OF SHARED SEGMENT */
+};
+
+#endif
diff --git a/include/linux/magic.h b/include/linux/magic.h
index 1fa0c2c..b41cc0a 100644
--- a/include/linux/magic.h
+++ b/include/linux/magic.h
@@ -5,6 +5,7 @@
 #define AFFS_SUPER_MAGIC	0xadff
 #define AFS_SUPER_MAGIC                0x5346414F
 #define AUTOFS_SUPER_MAGIC	0x0187
+#define CMSFS_SUPER_MAGIC	0xC3D4E2F1	/* 'CMS1' in EBCDIC */
 #define CODA_SUPER_MAGIC	0x73757245
 #define EFS_SUPER_MAGIC		0x414A53
 #define EXT2_SUPER_MAGIC	0xEF53
-- 
1.5.6.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 03/12] cmsfs: EBCDIC translation table
  2008-09-22  1:29 [RFC PATCH] CMS minidisk filesystem support Josef 'Jeff' Sipek
  2008-09-22  1:29 ` [PATCH 01/12] cmsfs: Documentation Josef 'Jeff' Sipek
  2008-09-22  1:29 ` [PATCH 02/12] cmsfs: header file Josef 'Jeff' Sipek
@ 2008-09-22  1:29 ` Josef 'Jeff' Sipek
  2008-09-22  1:29 ` [PATCH 04/12] cmsfs: block mapping code Josef 'Jeff' Sipek
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Josef 'Jeff' Sipek @ 2008-09-22  1:29 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: hch, Josef 'Jeff' Sipek

Currently, I am not aware of a generic (non-arch specific) way of
translating between ASCII and EBCDIC. Therefore, let's copy s390's tables
for the time being.

Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
---
 {arch/s390/kernel => fs/cmsfs}/ebcdic.c |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)
 copy {arch/s390/kernel => fs/cmsfs}/ebcdic.c (99%)

diff --git a/arch/s390/kernel/ebcdic.c b/fs/cmsfs/ebcdic.c
similarity index 99%
copy from arch/s390/kernel/ebcdic.c
copy to fs/cmsfs/ebcdic.c
index cc0dc60..bb0f973 100644
--- a/arch/s390/kernel/ebcdic.c
+++ b/fs/cmsfs/ebcdic.c
@@ -11,7 +11,6 @@
 
 #include <linux/module.h>
 #include <asm/types.h>
-#include <asm/ebcdic.h>
 
 /*
  * ASCII (IBM PC 437)  -> EBCDIC 037
-- 
1.5.6.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 04/12] cmsfs: block mapping code
  2008-09-22  1:29 [RFC PATCH] CMS minidisk filesystem support Josef 'Jeff' Sipek
                   ` (2 preceding siblings ...)
  2008-09-22  1:29 ` [PATCH 03/12] cmsfs: EBCDIC translation table Josef 'Jeff' Sipek
@ 2008-09-22  1:29 ` Josef 'Jeff' Sipek
  2008-09-22  1:29 ` [PATCH 05/12] cmsfs: file operations Josef 'Jeff' Sipek
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Josef 'Jeff' Sipek @ 2008-09-22  1:29 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: hch, Josef 'Jeff' Sipek

Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
---
 fs/cmsfs/bmap.c |  104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 104 insertions(+), 0 deletions(-)
 create mode 100644 fs/cmsfs/bmap.c

diff --git a/fs/cmsfs/bmap.c b/fs/cmsfs/bmap.c
new file mode 100644
index 0000000..ce9eccf
--- /dev/null
+++ b/fs/cmsfs/bmap.c
@@ -0,0 +1,104 @@
+/*
+ * CMSFS
+ *
+ *  (C) 2008  Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
+ *
+ * Based on cmsfs from 2.4.12-ac6:
+ *
+ *  (C) 2001  Rick Troth <rtroth@bmc.com>
+ *  (C) 2001  BMC Software, Inc., Houston, Texas, USA
+ *
+ */
+
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/buffer_head.h>
+#include <linux/mpage.h>
+
+#include "cmsfs.h"
+
+/**
+ * cmsfs_get_blocks - map a inode offset to a disk block
+ * @inode:	inode to map
+ * @iblock:	inode offset to map (in fs blocks)
+ * @bh_result:	resulting buffer_head
+ * @create:	?
+ */
+static int cmsfs_get_blocks(struct inode *inode, sector_t iblock,
+			    struct buffer_head *bh_result, int create)
+{
+	struct cmsfs_inode_info *cinode = CMSFS_I(inode);
+	struct super_block *sb = inode->i_sb;
+	struct buffer_head *bh;
+
+	BUG_ON(create);
+
+	/* indirection? */
+	if (cinode->level != 0) {
+		int ptrs_per_blk;
+		int i, lvl;
+		void *bp;
+		u32 b1, b2;
+
+		b2 = ~0; /* to avoid potentially uninit var warning */
+
+		/* pointers per block */
+		if (cinode->psize > 0)
+			ptrs_per_blk = CMSFS_SB(sb)->blksz / cinode->psize;
+		else
+			ptrs_per_blk = CMSFS_SB(sb)->blksz / 4;
+
+		/* read first block for indirection */
+		b1 = iblock;
+		for (i = 0; i < cinode->level; i++)
+			b1 = b1 / ptrs_per_blk;
+		bh = sb_bread(sb, cinode->origin - 1 + b1);
+		if (!bh)
+			goto fail;
+
+		for (lvl = 1; lvl <= cinode->level; lvl++) {
+			/*  read next block for indirection  */
+			b1 = iblock;
+			for (i = lvl; i < cinode->level; i++)
+				b1 = b1 / ptrs_per_blk;
+			b1 = b1 % ptrs_per_blk;
+			bp = bh->b_data;
+			bp += b1 * cinode->psize;
+			b2 = be32_to_cpu(*(u32*)bp);
+
+			brelse(bh);
+
+			/*  read next block for indirection  */
+			bh = sb_bread(sb, b2 - 1);
+			if (!bh)
+				goto fail;
+		}
+
+		clear_buffer_new(bh_result);
+		map_bh(bh_result, inode->i_sb, b2-1);
+	} else {
+		clear_buffer_new(bh_result);
+		map_bh(bh_result, inode->i_sb,
+		       cinode->origin - 1 + iblock);
+	}
+
+	return 0;
+
+fail:
+	return -EIO;
+}
+
+/**
+ * cmsfs_readpage - read a page for an inode
+ * @unused:	(unused)
+ * @page:	page to read
+ */
+static int cmsfs_readpage(struct file *unused, struct page *page)
+{
+	return mpage_readpage(page, cmsfs_get_blocks);
+}
+
+struct address_space_operations cmsfs_aops = {
+	.readpage	= cmsfs_readpage,
+};
-- 
1.5.6.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 05/12] cmsfs: file operations
  2008-09-22  1:29 [RFC PATCH] CMS minidisk filesystem support Josef 'Jeff' Sipek
                   ` (3 preceding siblings ...)
  2008-09-22  1:29 ` [PATCH 04/12] cmsfs: block mapping code Josef 'Jeff' Sipek
@ 2008-09-22  1:29 ` Josef 'Jeff' Sipek
  2008-09-22  1:29 ` [PATCH 06/12] cmsfs: inode operations Josef 'Jeff' Sipek
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Josef 'Jeff' Sipek @ 2008-09-22  1:29 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: hch, Josef 'Jeff' Sipek

Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
---
 fs/cmsfs/file.c |  204 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 204 insertions(+), 0 deletions(-)
 create mode 100644 fs/cmsfs/file.c

diff --git a/fs/cmsfs/file.c b/fs/cmsfs/file.c
new file mode 100644
index 0000000..26f23f8
--- /dev/null
+++ b/fs/cmsfs/file.c
@@ -0,0 +1,204 @@
+/*
+ * CMSFS
+ *
+ *  (C) 2008  Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
+ *
+ * Based on cmsfs from 2.4.12-ac6:
+ *
+ *  (C) 2001  Rick Troth <rtroth@bmc.com>
+ *  (C) 2001  BMC Software, Inc., Houston, Texas, USA
+ *
+ */
+
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include <linux/uaccess.h>
+
+#include "cmsfs.h"
+
+/**
+ * __read_recfm_fixed - read len bytes from file position pos
+ * @inode:	inode to read from
+ * @buf:	user buffer pointer to copy data to
+ * @len:	length of the buffer
+ * @pos:	position into the inode
+ */
+static ssize_t __read_recfm_fixed(struct inode *inode, char __user *buf,
+				  size_t len, loff_t pos)
+{
+	struct cmsfs_inode_info *ci = CMSFS_I(inode);
+	struct super_block *sb = inode->i_sb;
+	struct page *page;
+	unsigned char *kaddr;
+	u32 blkoff;
+	size_t err = -EIO;
+
+	BUG_ON(ci->recfm != RECFM_FIXED);
+	BUG_ON(sb->s_blocksize > PAGE_SIZE);
+
+	page = read_mapping_page(inode->i_mapping, pos >> PAGE_SHIFT, NULL);
+	if (IS_ERR(page))
+		return PTR_ERR(page);
+
+	kaddr = kmap(page);
+	if (PageError(page))
+		goto out;
+
+	blkoff = pos & ~PAGE_MASK;
+
+	/* won't read more than a page */
+	len = min(len, PAGE_SIZE - blkoff);
+
+	err = copy_to_user(buf, kaddr + blkoff, len);
+	if (!err)
+		err = len;
+
+out:
+	kunmap(page);
+	page_cache_release(page);
+	return err;
+}
+
+/**
+ * cmsfs_file_read - read from a file
+ * @file:	file to read from
+ * @buf:	user buffer pointer for data
+ * @len:	length of the buffer
+ * @ppos:	pointer to the file offset to read at
+ */
+static ssize_t cmsfs_file_read(struct file *file, char __user *buf, size_t len,
+			       loff_t *ppos)
+{
+	struct inode *inode = file->f_path.dentry->d_inode;
+	ssize_t ret;
+
+	if ((*ppos < inode->i_size) && (*ppos + len > inode->i_size))
+		len = inode->i_size - *ppos;
+	else if (*ppos >= inode->i_size)
+		return 0;
+
+	switch (CMSFS_I(inode)->recfm) {
+		case RECFM_FIXED:
+			ret = __read_recfm_fixed(inode, buf, len, *ppos);
+			break;
+		case RECFM_VAR:
+		default:
+			ret = -EINVAL;
+			break;
+	}
+
+	if (ret > 0)
+		*ppos = *ppos + ret;
+
+	return ret;
+}
+
+/**
+ * cmsfs_readdir - readdir
+ * @file:	file to readdir
+ * @dirent:	?
+ * @filldir:	readdir filler function ptr
+ */
+static int cmsfs_readdir(struct file *file, void *dirent, filldir_t filldir)
+{
+	struct inode *inode = file->f_path.dentry->d_inode;
+	struct super_block *sb = inode->i_sb;
+	struct cmsfs_inode_info *cinode = CMSFS_I(inode);
+	struct CMSFSFST *fst;
+	struct page *page;
+	char outname[18];
+	int i;
+	int err = 0;
+
+	if (inode->i_ino != CMSFS_DIRECTOR_INO)
+		return -ENOTDIR;
+
+	/* FIXME: this should go away, I think */
+	if (file->f_pos != 0)
+		return 0;
+
+	page = NULL;
+	fst = NULL;
+	file->f_pos = 0;
+
+	for (i = 0; i < cinode->items; i++, fst++) {
+		if ((i * cinode->lrecl) % CMSFS_SB(sb)->blksz == 0) {
+			if (i) {
+				kunmap(page);
+				page_cache_release(page);
+			}
+
+			page = read_mapping_page(inode->i_mapping,
+						 (i * cinode->lrecl) /
+						  CMSFS_SB(sb)->blksz,
+						 NULL);
+			if (IS_ERR(page)) {
+				err = PTR_ERR(page);
+				goto out;
+			}
+
+			fst = kmap(page);
+			if (PageError(page)) {
+				err = -EIO;
+				goto out_release;
+			}
+		}
+
+		/*
+		 * skipping .DIRECTOR and .ALLOCMAP, but using the dirent
+		 * space for the '.' and '..' entries
+		 */
+		if (i < 2) {
+			err = filldir(dirent, i ? ".." : ".",
+				      i ? 2 : 1, file->f_pos,
+				      CMSFS_DIRECTOR_INO,
+				      DT_DIR);
+			if (err)
+				break;
+			continue;
+		}
+
+		munge_name(fst->FSTFNAME, outname);
+
+		/* No subdirs so all files are regular */
+		err = filldir(dirent, outname, strlen(outname), file->f_pos,
+			      i + CMSFS_FIRST_INO, DT_REG);
+		if (err)
+			break;
+
+		/* set the file possition */
+		file->f_pos += cinode->lrecl;
+	}
+
+	kunmap(page);
+out_release:
+	page_cache_release(page);
+out:
+	return err;
+}
+
+/**
+ * cmsfs_file_open - open routine
+ * @inode:	inode to read
+ * @file:	file ptr to be associated with the inode
+ *
+ * NOTE: The only reason this exists is because it's a good place to prevent
+ * RECFM_VAR files being open, and later read. Once that's supported, this
+ * function should go away.
+ */
+static int cmsfs_file_open(struct inode *inode, struct file *file)
+{
+	if (CMSFS_I(inode)->recfm != RECFM_FIXED) {
+		printk("cmsfs: cannot open files with recfm != fixed\n");
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+struct file_operations cmsfs_file_ops = {
+	.readdir	= cmsfs_readdir,
+	.open		= cmsfs_file_open,
+	.read		= cmsfs_file_read,
+};
-- 
1.5.6.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 06/12] cmsfs: inode operations
  2008-09-22  1:29 [RFC PATCH] CMS minidisk filesystem support Josef 'Jeff' Sipek
                   ` (4 preceding siblings ...)
  2008-09-22  1:29 ` [PATCH 05/12] cmsfs: file operations Josef 'Jeff' Sipek
@ 2008-09-22  1:29 ` Josef 'Jeff' Sipek
  2008-09-22  1:29 ` [PATCH 07/12] cmsfs: super block operations Josef 'Jeff' Sipek
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Josef 'Jeff' Sipek @ 2008-09-22  1:29 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: hch, Josef 'Jeff' Sipek

Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
---
 fs/cmsfs/inode.c |  269 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 269 insertions(+), 0 deletions(-)
 create mode 100644 fs/cmsfs/inode.c

diff --git a/fs/cmsfs/inode.c b/fs/cmsfs/inode.c
new file mode 100644
index 0000000..9c4d51b
--- /dev/null
+++ b/fs/cmsfs/inode.c
@@ -0,0 +1,269 @@
+/*
+ * CMSFS
+ *
+ *  (C) 2008  Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
+ *
+ * Based on cmsfs from 2.4.12-ac6:
+ *
+ *  (C) 2001  Rick Troth <rtroth@bmc.com>
+ *  (C) 2001  BMC Software, Inc., Houston, Texas, USA
+ *
+ */
+
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+
+#include "cmsfs.h"
+
+/**
+ * cmsfs_inode_lookup - lookup a file in the directory
+ * @dir:	directory
+ * @dentry:	dentry to lookup
+ * @nd:		(unused)
+ */
+static struct dentry *cmsfs_lookup(struct inode *dir, struct dentry *dentry,
+				   struct nameidata *nd)
+{
+	struct cmsfs_inode_info *cdir = CMSFS_I(dir);
+	struct super_block *sb = dir->i_sb;
+	struct inode *inode;
+	struct page *page;
+	struct CMSFSFST *fst;
+	char outname[18];
+	int i;
+	int err;
+
+	if (dir->i_ino != CMSFS_DIRECTOR_INO)
+		return ERR_PTR(-ENOTDIR);
+
+	page = NULL;
+	inode = NULL;
+	fst = NULL;
+
+	for (i = 0; i < cdir->items; i++, fst++) {
+		if ((i * cdir->lrecl) % CMSFS_SB(sb)->blksz == 0) {
+			if (i) {
+				kunmap(page);
+				page_cache_release(page);
+			}
+
+			page = read_mapping_page(dir->i_mapping, (i * cdir->lrecl) /
+						 CMSFS_SB(sb)->blksz, NULL);
+			if (IS_ERR(page)) {
+				err = PTR_ERR(page);
+				goto out;
+			}
+
+			fst = kmap(page);
+			if (PageError(page)) {
+				err = -EIO;
+				goto out_release;
+			}
+		}
+
+		/* skipping .DIRECTOR and .ALLOCMAP, fill VFS dir with files */
+		if (i < 2)
+			continue;
+
+		munge_name(fst->FSTFNAME, outname);
+
+		if (!strncmp(outname, dentry->d_name.name, 17)) {
+			inode = cmsfs_iget(sb, i + CMSFS_FIRST_INO);
+			break;
+		}
+	}
+
+	kunmap(page);
+	page_cache_release(page);
+	return d_splice_alias(inode, dentry);
+
+out_release:
+	page_cache_release(page);
+out:
+	return ERR_PTR(err);
+}
+
+static struct inode_operations cmsfs_inode_ops = {
+        .lookup		= cmsfs_lookup,
+	.setxattr	= cmsfs_setxattr,
+	.getxattr	= cmsfs_getxattr,
+	.removexattr	= cmsfs_removexattr,
+	.listxattr	= cmsfs_listxattr,
+};
+
+/**
+ * cmsfs_set_inode_size - calculate and set the inode size
+ * @inode:	inode to work with
+ */
+static int cmsfs_set_inode_size(struct inode *inode)
+{
+	struct cmsfs_inode_info *cinode = CMSFS_I(inode);
+
+	/* the default - for safety */
+	inode->i_size = 0;
+
+	/*  if there are no records, then there ain't no bytes  */
+	if (cinode->items == 0)
+		return 0;
+
+	/*  how big is this file?  "it depends"  */
+	switch (cinode->recfm) {
+		case RECFM_FIXED:
+			inode->i_size = cinode->lrecl * cinode->items;
+			break;
+
+		case RECFM_VAR:
+			{
+				static int warned;
+				if (!warned)
+					printk(KERN_WARNING "cmsfs: recfm=v is"
+					       " unsuported\n");
+				warned=1;
+			}
+			break;
+
+		default:
+			BUG();
+	}
+
+	return 0;
+}
+
+/**
+ * read_inode - read an inode from DASD
+ * @inode:	inode to fill in
+ */
+static int read_inode(struct inode *inode)
+{
+	struct super_block *sb = inode->i_sb;
+	struct page *page;
+	struct CMSFSFST *fst, *buf;
+	int err;
+
+	if (inode->i_ino < CMSFS_FIRST_INO)
+		return -ENOENT;
+
+	page=NULL;
+	buf=NULL;
+
+	if (inode->i_ino != CMSFS_DIRECTOR_INO) {
+		/* read file block within the directory */
+		unsigned long ino = inode->i_ino - CMSFS_FIRST_INO;
+
+		page = read_mapping_page(sb->s_root->d_inode->i_mapping,
+					(ino * sizeof(struct CMSFSFST))/
+					 sb->s_blocksize, NULL);
+		if (IS_ERR(page)) {
+			err = PTR_ERR(page);
+			goto out;
+		}
+
+		fst = kmap(page);
+		if (PageError(page)) {
+			err = -EIO;
+			goto out_release;
+		}
+
+		fst = &fst[ino % (sb->s_blocksize / sizeof(struct CMSFSFST))];
+	} else {
+		/*
+		 * if we're reading the directory, we can't rely on
+		 * sb->s_root->d_inode to be set up, therefore we are forced
+		 * to do a block read
+		 */
+		buf = (struct CMSFSFST *)__get_free_page(GFP_KERNEL);
+		if(!buf)
+			return -ENOMEM;
+
+		err = 0;
+		if (cmsfs_read_block(sb, buf, CMSFS_SB(sb)->origin-1,
+				     sb->s_blocksize) != sb->s_blocksize) {
+			err = -EIO;
+			goto out;
+		}
+
+		fst = buf;
+	}
+
+	CMSFS_I(inode)->recfm  = (enum recfm) fst->FSTRECFM;
+	CMSFS_I(inode)->lrecl  = be32_to_cpu(fst->FSTLRECL);
+	CMSFS_I(inode)->origin = be32_to_cpu(fst->FSTFOP);
+	CMSFS_I(inode)->blocks = be32_to_cpu(fst->FSTADBC);
+	CMSFS_I(inode)->items  = be32_to_cpu(fst->FSTAIC);
+
+	/*  levels of indirection and pointer size  */
+	CMSFS_I(inode)->level  = fst->FSTNLVL;
+	CMSFS_I(inode)->psize  = fst->FSTPTRSZ;
+
+	CMSFS_I(inode)->ctime = mktime(hex2int(fst->FSTADATI[0]) +
+				       (fst->FSTFLAGS & FSTCNTRY ? 2000 : 1900),
+				       hex2int(fst->FSTADATI[1] - 1),
+				       hex2int(fst->FSTADATI[2]),
+				       hex2int(fst->FSTADATI[3]),
+				       hex2int(fst->FSTADATI[4]),
+				       hex2int(fst->FSTADATI[5]));
+
+	err = 0;
+
+out:
+	if (inode->i_ino != CMSFS_DIRECTOR_INO) {
+		kunmap(page);
+out_release:
+		page_cache_release(page);
+	} else
+		free_page((unsigned long)buf);
+
+	return err;
+}
+
+/**
+ * cmsfs_iget - get a filled-in inode based on inode number
+ * @sb:		superblock to read inode from
+ * @ino:	inode number to look up
+ */
+struct inode *cmsfs_iget(struct super_block *sb, unsigned long ino)
+{
+	struct inode *inode;
+	int err = 0;
+
+	inode = iget_locked(sb, ino);
+	if (!inode)
+		return ERR_PTR(-ENOMEM);
+	if (!(inode->i_state & I_NEW))
+		return inode;
+
+	if ((err = read_inode(inode)))
+		goto bad_inode;
+
+	if (cmsfs_set_inode_size(inode))
+		goto bad_inode;
+
+	if (inode->i_ino == CMSFS_DIRECTOR_INO)
+		inode->i_mode = S_IRWXUGO | S_IFDIR;
+	else
+		inode->i_mode = S_IRUGO | S_IWUGO | S_IFREG;
+	inode->i_uid = 0;
+	inode->i_gid = 0;
+	inode->i_nlink = 1;
+	inode->i_blocks = CMSFS_I(inode)->blocks;
+	inode->i_atime.tv_sec = CMSFS_I(inode)->ctime;
+	inode->i_ctime.tv_sec = CMSFS_I(inode)->ctime;
+	inode->i_mtime.tv_sec = CMSFS_I(inode)->ctime;
+	inode->i_atime.tv_nsec = 0;
+	inode->i_ctime.tv_nsec = 0;
+	inode->i_mtime.tv_nsec = 0;
+
+	inode->i_generation = 0;
+
+	inode->i_op  = &cmsfs_inode_ops;
+	inode->i_fop = &cmsfs_file_ops;
+	inode->i_mapping->a_ops = &cmsfs_aops;
+
+	unlock_new_inode(inode);
+	return inode;
+
+bad_inode:
+	iget_failed(inode);
+	return ERR_PTR(err);
+}
-- 
1.5.6.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 07/12] cmsfs: super block operations
  2008-09-22  1:29 [RFC PATCH] CMS minidisk filesystem support Josef 'Jeff' Sipek
                   ` (5 preceding siblings ...)
  2008-09-22  1:29 ` [PATCH 06/12] cmsfs: inode operations Josef 'Jeff' Sipek
@ 2008-09-22  1:29 ` Josef 'Jeff' Sipek
  2008-09-22  1:29 ` [PATCH 08/12] cmsfs: export extra file attributes via xattr Josef 'Jeff' Sipek
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Josef 'Jeff' Sipek @ 2008-09-22  1:29 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: hch, Josef 'Jeff' Sipek

Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
---
 fs/cmsfs/super.c |  379 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 379 insertions(+), 0 deletions(-)
 create mode 100644 fs/cmsfs/super.c

diff --git a/fs/cmsfs/super.c b/fs/cmsfs/super.c
new file mode 100644
index 0000000..a397b09
--- /dev/null
+++ b/fs/cmsfs/super.c
@@ -0,0 +1,379 @@
+/*
+ * CMSFS
+ *
+ *  (C) 2008  Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
+ *
+ * Based on cmsfs from 2.4.12-ac6:
+ *
+ *  (C) 2001  Rick Troth <rtroth@bmc.com>
+ *  (C) 2001  BMC Software, Inc., Houston, Texas, USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+
+#include <linux/magic.h>
+#include <linux/statfs.h>
+
+#include "cmsfs.h"
+
+static struct kmem_cache *cmsfs_inode_cachep = NULL;
+
+/*
+ * Blocksize test array - possible block sizes for a CMS "EDF" minidisk
+ * filesystem
+ */
+static int blksizes[] = { 512, 1024, 2048, 4096, 0, };
+
+/**
+ * cmsfs_find_label - look for the CMS volume label structure (ADT)
+ * @sb:		superblock to operate on
+ * @adt:	ADT structure to fill in
+ *
+ * Tries various block sizes to find the CMSFS_SUPER_MAGIC. When found,
+ * sb->s_blocksize is updated apropriately, and the adt is filled in
+ */
+static int cmsfs_find_label(struct super_block *sb, struct CMSFSADT *adt)
+{
+	void *buf;
+	int i;
+	int err;
+
+	buf = (void *)__get_free_page(GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	err = -EIO;
+
+	/*
+	 *  FBA DASDs are special.  Physical blocksize is always 512
+	 *  and the label is at physical offset 512 (second record),
+	 *  though the logical blocksize may be 512, 1K, 2K, or 4K.
+	 */
+	if (sb->s_blocksize == 512) {
+		/*  read FBA block #1 (second record)  */
+		if (cmsfs_read_block(sb, buf, 1, 512) != 512)
+			goto out;
+
+		memcpy(adt, buf, sizeof(*adt));
+
+		/*  check for the CMS1 magic at the FBA offset  */
+		if (be32_to_cpu(adt->ADTIDENT) == CMSFS_SUPER_MAGIC) {
+			u32 blksz;
+
+			blksz = be32_to_cpu(adt->ADTDBSIZ);
+			if (blksz != 512) {
+				printk(KERN_WARNING "cmsfs: FS blocksize"
+				       " does not match device blocksize"
+				       " (%u != %d).\n", blksz, 512);
+			} else {
+				CMSFS_SB(sb)->blksz = 512;
+
+				err = 0;
+			}
+
+			goto out;
+		}
+	}
+
+	/*  not an FBA volume; try CKD blocksizes
+	 *
+	 *  CKD DASDs are C/H/S in nature and can have any blocksize
+	 *  that the utility or operating system decided to put there.
+	 *  OS/390 uses no particular blocksize, referring to tracks
+	 *  directly. For CMS CKD volumes, the physical blocksize should
+	 *  match logical, unless obscured by the access method.
+	 */
+	for (i = 0; blksizes[i] != 0; i++) {
+		u32 blksz;
+
+		if (sb->s_blocksize != blksizes[i])
+			continue;
+
+		/*  read CKD block #2 (third record)  */
+		if (cmsfs_read_block(sb, buf, 2, blksizes[i]) != blksizes[i])
+			continue;
+
+		memcpy(adt, buf, sizeof(*adt));
+
+		/*  check for the CMS1 magic  */
+		if (be32_to_cpu(adt->ADTIDENT) != CMSFS_SUPER_MAGIC)
+			continue;
+
+		blksz = be32_to_cpu(adt->ADTDBSIZ);
+		if (blksz == blksizes[i]) {
+			CMSFS_SB(sb)->blksz = blksz;
+
+			sb_min_blocksize(sb, blksz);
+
+			err = 0;
+			goto out;
+		}
+
+		printk(KERN_WARNING "cmsfs: FS blocksize does not match"
+		       " device blocksize (%u != %d).\n", blksz, blksizes[i]);
+		goto out;
+	}
+
+	err = -ENOMEDIUM;
+
+out:
+	free_page((unsigned long)buf);
+	return err;
+}
+
+/**
+ * __fill_super - fill in superblock private data
+ * @sb:		superblock to operate on
+ *
+ * Find the ADT struct on the disk, read in the data, byteswap if necessary,
+ * and then will in CMSFS_SB(sb).
+ */
+static int __fill_super(struct super_block *sb)
+{
+	struct CMSFSADT cmsvol; /* partial "ADT" structure */
+	struct cmsfs_sb_info *sbi = CMSFS_SB(sb);
+	struct inode *root;
+	int err;
+
+	BUG_ON(!sbi);
+
+	/*
+	 * look for the CMS volume label (aka VOLSER)
+	 *
+	 * NOTE: This also effects a load of the ADT struct to &cmsvol and
+	 * sets the blksz member to match the volume found
+	 */
+	err = cmsfs_find_label(sb, &cmsvol);
+	if (err)
+		return err;
+
+	/* extract volume label */
+	memcpy(sbi->volid, cmsvol.ADTID, 6);
+	sbi->volid[6] = 0x00;
+
+	/* extract "directory origin pointer" */
+	sbi->origin = be32_to_cpu(cmsvol.ADTDOP);
+
+	/* extract number of cylinders used */
+	sbi->ncyls = be32_to_cpu(cmsvol.ADTCYL);
+
+	/* extract max number of cylinders */
+	sbi->mcyls = be32_to_cpu(cmsvol.ADTMCYL);
+
+	/* extract "total blocks on disk" count */
+	sbi->blocks = be32_to_cpu(cmsvol.ADTNUM);
+
+	/* compute "blocks used" count */
+	sbi->bkused = be32_to_cpu(cmsvol.ADTUSED);
+	sbi->bkused += 1;	/* why??? */
+
+	/* extract size and number of FSTs */
+	sbi->fstsz = be32_to_cpu(cmsvol.ADTFSTSZ);
+	sbi->fstct = be32_to_cpu(cmsvol.ADTNFST);
+
+	/* extract offset to reserved file, if any */
+	sbi->resoff = be32_to_cpu(cmsvol.ADTOFFST);
+
+	sbi->ctime = mktime(hex2int(cmsvol.ADTDCRED[0]) +
+				    (cmsvol.ADTFLGL & ADTCNTRY ? 2000 : 1900),
+				    hex2int(cmsvol.ADTDCRED[1] - 1),
+				    hex2int(cmsvol.ADTDCRED[2]),
+				    hex2int(cmsvol.ADTDCRED[3]),
+				    hex2int(cmsvol.ADTDCRED[4]),
+				    hex2int(cmsvol.ADTDCRED[5]));
+
+	err = -ENOMEM;
+	root = cmsfs_iget(sb, CMSFS_DIRECTOR_INO);
+	if (IS_ERR(root)) {
+		err = PTR_ERR(root);
+		goto out;
+	}
+
+	sb->s_root = d_alloc_root(root);
+	if (!sb->s_root) {
+		printk(KERN_ERR "cmsfs: get root inode failed\n");
+		goto out_inode;
+	}
+
+	err = -EUCLEAN;
+
+	/*  sanity check: FOP in dir entry must match DOP in vol  */
+	if (CMSFS_I(root)->origin != CMSFS_SB(sb)->origin) {
+		printk("cmsfs: directory FOP != volume DOP\n");
+		goto out_inode;
+	}
+
+	/* sanity check: RECFM of a directory must be fixed */
+	if (CMSFS_I(root)->recfm != RECFM_FIXED) {
+		printk("cmsfs: directory must have recfm fixed.\n");
+		goto out_inode;
+	}
+
+	/* sanity check: LRECL of a directory must be 64 */
+	if (CMSFS_I(root)->lrecl != 64) {
+		printk(KERN_WARNING "cmsfs: directory lrecl %d not 64.\n",
+		       CMSFS_I(root)->lrecl);
+		goto out_inode;
+	}
+
+	sbi->files = CMSFS_I(root)->items;
+
+	sb->s_flags |= MS_RDONLY;
+	sb->s_maxbytes = MAX_NON_LFS;
+
+	err = 0;
+out:
+	return err;
+
+out_inode:
+	iput(root);
+	goto out;
+}
+
+/**
+ * cmsfs_alloc_inode - allocate a VFS+cmsfs inode structs
+ * @sb:		superblock to work with
+ */
+static struct inode *cmsfs_alloc_inode(struct super_block *sb)
+{
+	struct cmsfs_inode_info *cinode;
+
+	cinode = kmem_cache_alloc(cmsfs_inode_cachep, GFP_NOFS);
+	if (!cinode)
+		return NULL;
+
+	return &cinode->vfs_inode;
+}
+
+/**
+ * cmsfs_destroy_inode - free VFS+cmsfs inode structs
+ * @inode:	inode to free
+ */
+static void cmsfs_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(cmsfs_inode_cachep, CMSFS_I(inode));
+}
+
+/**
+ * cmsfs_statfs - return stat information
+ * @dentry:	destry being stat'd
+ * @buf:	stat buffer to fill
+ */
+static int cmsfs_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+	struct cmsfs_sb_info *sbi = CMSFS_SB(dentry->d_sb);
+
+	buf->f_type    = CMSFS_SUPER_MAGIC;
+	buf->f_bsize   = sbi->blksz;
+	buf->f_blocks  = sbi->blocks;
+	buf->f_bfree   = sbi->blocks - sbi->bkused;
+	buf->f_bavail  = sbi->blocks - sbi->bkused;
+
+	buf->f_files   = sbi->files;
+	buf->f_ffree   = 0; /*  no files available on R/O media  */
+
+	buf->f_namelen = CMSFS_NAME_LEN;
+
+	memset(buf->f_fsid.val, 0, 8);
+	memcpy(buf->f_fsid.val, sbi->volid, 6);
+
+	return 0;
+}
+
+static struct super_operations cmsfs_sops = {
+	.alloc_inode	= cmsfs_alloc_inode,
+	.destroy_inode	= cmsfs_destroy_inode,
+        .statfs		= cmsfs_statfs,
+};
+
+/**
+ * cmsfs_fill_super - fill in a superblock
+ * @sb:		superblock to fill
+ * @data:	(unused)
+ * @silent:	don't printk anything
+ */
+static int cmsfs_fill_super(struct super_block *sb, void *data, int silent)
+{
+	struct cmsfs_sb_info *sbi;
+	int err;
+
+	sbi = kzalloc(sizeof(struct cmsfs_sb_info), GFP_KERNEL);
+	if (!sbi)
+		return -ENOMEM;
+	sb->s_fs_info = sbi;
+
+	sb->s_magic = CMSFS_SUPER_MAGIC;
+	sb->s_op = &cmsfs_sops;
+
+	sb_min_blocksize(sb, 512);
+
+	if ((err = __fill_super(sb))) {
+		kfree(sb->s_fs_info);
+		sb->s_fs_info = NULL;
+		return err;
+	}
+
+	return 0;
+}
+
+static int cmsfs_get_sb(struct file_system_type *fs_type,
+			int flags, const char *dev_name,
+			void *data, struct vfsmount *mnt)
+{
+	return get_sb_bdev(fs_type, flags, dev_name, data, cmsfs_fill_super,
+			   mnt);
+}
+
+static struct file_system_type cmsfs_type = {
+	.owner		= THIS_MODULE,
+	.name		= "cmsfs",
+	.get_sb		= cmsfs_get_sb,
+	.kill_sb	= kill_block_super,
+	.fs_flags	= FS_REQUIRES_DEV,
+};
+
+static void cmsfs_inode_init_once(void *data)
+{
+	struct cmsfs_inode_info *cinode = data;
+
+	memset(cinode, 0, sizeof(struct cmsfs_inode_info));
+
+	inode_init_once(&cinode->vfs_inode);
+}
+
+static int cmsfs_init(void)
+{
+	int err;
+	printk(KERN_INFO "CMSFS\n");
+
+	cmsfs_inode_cachep = kmem_cache_create("cmsfs_inode_cache",
+					       sizeof(struct cmsfs_inode_info),
+					       0, 0,
+					       cmsfs_inode_init_once);
+	if (!cmsfs_inode_cachep)
+		return -ENOMEM;
+
+	err = register_filesystem(&cmsfs_type);
+	if (err)
+		kmem_cache_destroy(cmsfs_inode_cachep);
+
+	return err;
+}
+
+static void cmsfs_cleanup(void)
+{
+	unregister_filesystem(&cmsfs_type);
+	kmem_cache_destroy(cmsfs_inode_cachep);
+	return;
+}
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("CMS Minidisk filesystem Support");
+MODULE_AUTHOR("Josef 'Jeff' Sipek <jeffpc@josefsipek.net>");
+
+module_init(cmsfs_init);
+module_exit(cmsfs_cleanup);
-- 
1.5.6.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 08/12] cmsfs: export extra file attributes via xattr
  2008-09-22  1:29 [RFC PATCH] CMS minidisk filesystem support Josef 'Jeff' Sipek
                   ` (6 preceding siblings ...)
  2008-09-22  1:29 ` [PATCH 07/12] cmsfs: super block operations Josef 'Jeff' Sipek
@ 2008-09-22  1:29 ` Josef 'Jeff' Sipek
  2008-09-22  1:29 ` [PATCH 09/12] cmsfs: misc helpers Josef 'Jeff' Sipek
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Josef 'Jeff' Sipek @ 2008-09-22  1:29 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: hch, Josef 'Jeff' Sipek

Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
---
 fs/cmsfs/xattr.c |   74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 74 insertions(+), 0 deletions(-)
 create mode 100644 fs/cmsfs/xattr.c

diff --git a/fs/cmsfs/xattr.c b/fs/cmsfs/xattr.c
new file mode 100644
index 0000000..df48aed
--- /dev/null
+++ b/fs/cmsfs/xattr.c
@@ -0,0 +1,74 @@
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+
+#include <linux/errno.h>
+
+#include "cmsfs.h"
+
+ssize_t cmsfs_getxattr(struct dentry *dentry, const char *name, void *value,
+		       size_t size)
+{
+	char tmp[16];
+	char *out = NULL;
+
+	if (!strcmp("system.recfm", name)) {
+		switch (CMSFS_I(dentry->d_inode)->recfm) {
+			case RECFM_FIXED:
+				out = "fixed";
+				break;
+			case RECFM_VAR:
+				out = "variable";
+				break;
+			default:
+				out = "???";
+				break;
+		}
+	} else if (!strcmp("system.lrecl", name)) {
+		snprintf(tmp, 16, "%d", CMSFS_I(dentry->d_inode)->lrecl);
+		out = tmp;
+	} else if (!strcmp("system.items", name)) {
+		snprintf(tmp, 16, "%d", CMSFS_I(dentry->d_inode)->items);
+		out = tmp;
+	}
+
+	if (!out)
+		return -ENODATA;
+
+	if (!value && !size)
+		return strlen(out);
+
+	if (size < strlen(out))
+		return -ERANGE;
+
+	strcpy(value, out);
+
+	return strlen(out);
+}
+
+#define ATTRLIST "system.recfm\0system.lrecl\0system.items\0"
+
+ssize_t cmsfs_listxattr(struct dentry *dentry, char *list, size_t size)
+{
+	if (!list || !size)
+		return sizeof(ATTRLIST);
+
+	if (size < sizeof(ATTRLIST))
+		return -ERANGE;
+
+	memcpy(list, ATTRLIST, sizeof(ATTRLIST));
+
+	return sizeof(ATTRLIST);
+}
+
+int cmsfs_setxattr(struct dentry *dentry, const char *name, const void *value,
+		   size_t size, int flags)
+{
+	return -EOPNOTSUPP;
+}
+
+int cmsfs_removexattr(struct dentry *dentry, const char *name)
+{
+	return -EOPNOTSUPP;
+}
-- 
1.5.6.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 09/12] cmsfs: misc helpers
  2008-09-22  1:29 [RFC PATCH] CMS minidisk filesystem support Josef 'Jeff' Sipek
                   ` (7 preceding siblings ...)
  2008-09-22  1:29 ` [PATCH 08/12] cmsfs: export extra file attributes via xattr Josef 'Jeff' Sipek
@ 2008-09-22  1:29 ` Josef 'Jeff' Sipek
  2008-09-22  1:29 ` [PATCH 10/12] MAINTAINERS: cmsfs entry Josef 'Jeff' Sipek
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Josef 'Jeff' Sipek @ 2008-09-22  1:29 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: hch, Josef 'Jeff' Sipek

Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
---
 fs/cmsfs/helpers.c |   78 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 78 insertions(+), 0 deletions(-)
 create mode 100644 fs/cmsfs/helpers.c

diff --git a/fs/cmsfs/helpers.c b/fs/cmsfs/helpers.c
new file mode 100644
index 0000000..93800b3
--- /dev/null
+++ b/fs/cmsfs/helpers.c
@@ -0,0 +1,78 @@
+/*
+ * CMSFS
+ *
+ *  (C) 2008  Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
+ *
+ * Based on cmsfs from 2.4.12-ac6:
+ *
+ *  (C) 2001  Rick Troth <rtroth@bmc.com>
+ *  (C) 2001  BMC Software, Inc., Houston, Texas, USA
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/buffer_head.h>
+
+#include "cmsfs.h"
+
+void munge_name(__u8 *name, char *outname)
+{
+	__u8 *p = name;
+	char *orig_outname = outname;
+
+	if (!name)
+		return;
+
+	/*
+	 * NOTE:
+	 *   '\x40' is a space in EBCDIC
+	 *   '\x4b' is a period in EBCDIC
+	 */
+
+	/* file name */
+	while(*p != '\x40' && (p - name < 8))
+		*outname++ = *p++;
+
+	*outname++ = '\x4b';
+
+	p = name+8;
+
+	while(*p != '\x40' && (p - name < 16))
+		*outname++ = *p++;
+
+	*outname = '\0';
+
+	EBC2ASC(orig_outname, 17);
+}
+
+/**
+ * cmsfs_read_block - read a single disk block
+ * @sb:		superblock to read from
+ * @buf:	buffer to fill
+ * @block:	block number to read
+ * @blocksize:	blocksize to use
+ */
+int cmsfs_read_block(struct super_block *sb, void *buf, int block,
+		     unsigned blocksize)
+{
+	struct buffer_head * bh;
+
+	/*  for the moment,  we only deal with physical blocks  */
+	BUG_ON(blocksize != sb->s_blocksize);
+
+	/* We could maybe handle that case by breaking-up this call into
+	   multiple bread() calls, but that'll be a later driver rev.  */
+
+	/* Call the system-level __bread() */
+	bh = __bread(sb->s_bdev, block, blocksize);
+	if (!bh) {
+		printk(KERN_WARNING "cmsfs: system bread() failed.\n");
+		return -EIO;
+	}
+
+	/* copy the data part,  then release the VFS buffer */
+	memmove(buf, bh->b_data, blocksize);
+	brelse(bh);
+
+	return blocksize;
+}
-- 
1.5.6.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 10/12] MAINTAINERS: cmsfs entry
  2008-09-22  1:29 [RFC PATCH] CMS minidisk filesystem support Josef 'Jeff' Sipek
                   ` (8 preceding siblings ...)
  2008-09-22  1:29 ` [PATCH 09/12] cmsfs: misc helpers Josef 'Jeff' Sipek
@ 2008-09-22  1:29 ` Josef 'Jeff' Sipek
  2008-09-22  1:29 ` [PATCH 11/12] cmsfs: Kconfig entry Josef 'Jeff' Sipek
  2008-09-22  1:29 ` [PATCH 12/12] cmsfs: Makefile Josef 'Jeff' Sipek
  11 siblings, 0 replies; 13+ messages in thread
From: Josef 'Jeff' Sipek @ 2008-09-22  1:29 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: hch, Josef 'Jeff' Sipek

Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
---
 MAINTAINERS |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 663485b..90a2fbd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1187,6 +1187,11 @@ P:	Nils Faerber (port to kernel 2.4)
 M:	Nils Faerber <nils@kernelconcepts.de>
 S:	Maintained
 
+CMSFS FILE SYSTEM
+P:	Josef 'Jeff' Sipek
+M:	jeffpc@josefsipek.net
+S:	Maintained
+
 CODA FILE SYSTEM
 P:	Jan Harkes
 M:	jaharkes@cs.cmu.edu
-- 
1.5.6.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 11/12] cmsfs: Kconfig entry
  2008-09-22  1:29 [RFC PATCH] CMS minidisk filesystem support Josef 'Jeff' Sipek
                   ` (9 preceding siblings ...)
  2008-09-22  1:29 ` [PATCH 10/12] MAINTAINERS: cmsfs entry Josef 'Jeff' Sipek
@ 2008-09-22  1:29 ` Josef 'Jeff' Sipek
  2008-09-22  1:29 ` [PATCH 12/12] cmsfs: Makefile Josef 'Jeff' Sipek
  11 siblings, 0 replies; 13+ messages in thread
From: Josef 'Jeff' Sipek @ 2008-09-22  1:29 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: hch, Josef 'Jeff' Sipek

Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
---
 fs/Kconfig |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/fs/Kconfig b/fs/Kconfig
index d387358..de25ab0 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1033,6 +1033,14 @@ config AFFS_FS
 	  To compile this file system support as a module, choose M here: the
 	  module will be called affs.  If unsure, say N.
 
+config CMS_FS
+	tristate "CMS minidisk filesystem support (EXPERIMENTAL)"
+	depends on BLOCK && EXPERIMENTAL
+	help
+	  Support for z/VM CMS minidisk filesystem format.
+
+	  If unsure, say N.
+
 config ECRYPT_FS
 	tristate "eCrypt filesystem layer support (EXPERIMENTAL)"
 	depends on EXPERIMENTAL && KEYS && CRYPTO && NET
-- 
1.5.6.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 12/12] cmsfs: Makefile
  2008-09-22  1:29 [RFC PATCH] CMS minidisk filesystem support Josef 'Jeff' Sipek
                   ` (10 preceding siblings ...)
  2008-09-22  1:29 ` [PATCH 11/12] cmsfs: Kconfig entry Josef 'Jeff' Sipek
@ 2008-09-22  1:29 ` Josef 'Jeff' Sipek
  11 siblings, 0 replies; 13+ messages in thread
From: Josef 'Jeff' Sipek @ 2008-09-22  1:29 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: hch, Josef 'Jeff' Sipek

Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
---
 fs/Makefile       |    1 +
 fs/cmsfs/Makefile |    3 +++
 2 files changed, 4 insertions(+), 0 deletions(-)
 create mode 100644 fs/cmsfs/Makefile

diff --git a/fs/Makefile b/fs/Makefile
index a1482a5..3aa1749 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -76,6 +76,7 @@ obj-$(CONFIG_EXT2_FS)		+= ext2/
 obj-$(CONFIG_CRAMFS)		+= cramfs/
 obj-y				+= ramfs/
 obj-$(CONFIG_HUGETLBFS)		+= hugetlbfs/
+obj-$(CONFIG_CMS_FS)		+= cmsfs/
 obj-$(CONFIG_CODA_FS)		+= coda/
 obj-$(CONFIG_MINIX_FS)		+= minix/
 obj-$(CONFIG_FAT_FS)		+= fat/
diff --git a/fs/cmsfs/Makefile b/fs/cmsfs/Makefile
new file mode 100644
index 0000000..bb6f5ba
--- /dev/null
+++ b/fs/cmsfs/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_CMS_FS)	+= cmsfs.o
+
+cmsfs-y			+= super.o inode.o file.o bmap.o helpers.o ebcdic.o xattr.o
-- 
1.5.6.3


^ permalink raw reply related	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2008-09-22  1:47 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-09-22  1:29 [RFC PATCH] CMS minidisk filesystem support Josef 'Jeff' Sipek
2008-09-22  1:29 ` [PATCH 01/12] cmsfs: Documentation Josef 'Jeff' Sipek
2008-09-22  1:29 ` [PATCH 02/12] cmsfs: header file Josef 'Jeff' Sipek
2008-09-22  1:29 ` [PATCH 03/12] cmsfs: EBCDIC translation table Josef 'Jeff' Sipek
2008-09-22  1:29 ` [PATCH 04/12] cmsfs: block mapping code Josef 'Jeff' Sipek
2008-09-22  1:29 ` [PATCH 05/12] cmsfs: file operations Josef 'Jeff' Sipek
2008-09-22  1:29 ` [PATCH 06/12] cmsfs: inode operations Josef 'Jeff' Sipek
2008-09-22  1:29 ` [PATCH 07/12] cmsfs: super block operations Josef 'Jeff' Sipek
2008-09-22  1:29 ` [PATCH 08/12] cmsfs: export extra file attributes via xattr Josef 'Jeff' Sipek
2008-09-22  1:29 ` [PATCH 09/12] cmsfs: misc helpers Josef 'Jeff' Sipek
2008-09-22  1:29 ` [PATCH 10/12] MAINTAINERS: cmsfs entry Josef 'Jeff' Sipek
2008-09-22  1:29 ` [PATCH 11/12] cmsfs: Kconfig entry Josef 'Jeff' Sipek
2008-09-22  1:29 ` [PATCH 12/12] cmsfs: Makefile Josef 'Jeff' Sipek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).