* [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).