[PATCH 07/12] cmsfs: super block operations

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Signed-off-by: Josef 'Jeff' Sipek <jeffpc@xxxxxxxxxxxxxx>
---
 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@xxxxxxxxxxxxxx>
+ *
+ * Based on cmsfs from 2.4.12-ac6:
+ *
+ *  (C) 2001  Rick Troth <rtroth@xxxxxxx>
+ *  (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@xxxxxxxxxxxxxx>");
+
+module_init(cmsfs_init);
+module_exit(cmsfs_cleanup);
-- 
1.5.6.3

--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux