[PATCH 06/12] cmsfs: inode operations

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

 



Signed-off-by: Josef 'Jeff' Sipek <jeffpc@xxxxxxxxxxxxxx>
---
 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@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/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

--
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