changeset 512:cb3926aac584

cp/fs: rewrite the EDF code to use the block cache Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
date Mon, 25 Apr 2011 09:15:29 -0400
parents 162125ad17ee
children c5b9bc302571
files cp/fs/edf.c cp/include/edf.h cp/nucleus/config.c
diffstat 3 files changed, 183 insertions(+), 109 deletions(-) [+]
line wrap: on
line diff
--- a/cp/fs/edf.c	Mon Apr 25 09:15:18 2011 -0400
+++ b/cp/fs/edf.c	Mon Apr 25 09:15:29 2011 -0400
@@ -12,10 +12,80 @@
 #include <bdev.h>
 #include <ebcdic.h>
 #include <edf.h>
+#include <bcache.h>
 
 static LOCK_CLASS(edf_fs);
+static LOCK_CLASS(edf_dir);
 static LOCK_CLASS(edf_file);
 
+/* assumes that fs->lock is held */
+struct file *__alloc_file(struct fs *fs, struct FST *fst)
+{
+	struct file *file;
+
+	file = malloc(sizeof(struct file), ZONE_NORMAL);
+	if (!file)
+		return ERR_PTR(-ENOMEM);
+
+	memset(file, 0, sizeof(struct file));
+
+	if (fst)
+		memcpy(&file->FST, fst, sizeof(struct FST));
+
+	INIT_LIST_HEAD(&file->files);
+	INIT_LIST_HEAD(&file->bcache);
+	mutex_init(&file->lock, &edf_file);
+
+	file->fs = fs;
+
+	list_add_tail(&file->files, &fs->files);
+
+	return file;
+}
+
+/* assumes that fs->lock is held */
+void __free_file(struct file *file)
+{
+	list_del(&file->files);
+	free(file);
+}
+
+int __init_dir(struct fs *fs, void *tmp)
+{
+	struct FST *fst = tmp;
+	struct file *file;
+	int ret;
+
+	ret = bdev_read_block(fs->dev, tmp, fs->ADT.DOP);
+	if (ret)
+		return ret;
+
+	if (memcmp(fst[0].FNAME, DIRECTOR_FN, 8) ||
+	    memcmp(fst[0].FTYPE, DIRECTOR_FT, 8) ||
+	    (fst[0].RECFM != FSTDFIX) ||
+	    memcmp(fst[1].FNAME, ALLOCMAP_FN, 8) ||
+	    memcmp(fst[1].FTYPE, ALLOCMAP_FT, 8) ||
+	    (fst[1].RECFM != FSTDFIX))
+		return -ECORRUPT;
+
+	file = __alloc_file(fs, &fst[0]);
+	if (IS_ERR(file))
+		return PTR_ERR(file);
+
+	/* need to override the default lock class */
+	mutex_init(&file->lock, &edf_dir);
+
+	ret = bcache_add(file, 0, 0, fs->ADT.DOP);
+	if (ret) {
+		__free_file(file);
+		return ret;
+	}
+
+	fs->dir = file;
+
+	return 0;
+}
+
 struct fs *edf_mount(struct device *dev)
 {
 	struct page *page;
@@ -41,17 +111,23 @@
 	mutex_init(&fs->lock, &edf_fs);
 	INIT_LIST_HEAD(&fs->files);
 	fs->dev = dev;
-	fs->tmp_buf = tmp;
 
 	memcpy(&fs->ADT, tmp, sizeof(struct ADT));
 
 	ret = -EINVAL;
-	if ((fs->ADT.ADTIDENT != __ADTIDENT) ||
-	    (fs->ADT.ADTDBSIZ != EDF_SUPPORTED_BLOCK_SIZE) ||
-	    (fs->ADT.ADTOFFST != 0) ||
-	    (fs->ADT.ADTFSTSZ != sizeof(struct FST)))
+	if ((fs->ADT.IDENT != __ADTIDENT) ||
+	    (fs->ADT.DBSIZ != EDF_SUPPORTED_BLOCK_SIZE) ||
+	    (fs->ADT.OFFST != 0) ||
+	    (fs->ADT.FSTSZ != sizeof(struct FST)))
 		goto out_free;
 
+	ret = __init_dir(fs, tmp);
+	if (ret)
+		goto out_free;
+
+	/* FIXME: init the ALLOCMAP */
+
+	free_pages(tmp, 0);
 	return fs;
 
 out_free:
@@ -60,26 +136,16 @@
 	return ERR_PTR(ret);
 }
 
-extern struct console *oper_con;
 struct file *edf_lookup(struct fs *fs, char *fn, char *ft)
 {
 	char __fn[8];
 	char __ft[8];
-	struct page *page;
 	struct file *file;
-	struct file *tmpf;
 	struct FST *fst;
-	long ret;
-	int found;
+	u32 blk;
+	int ret;
 	int i;
 
-	file = malloc(sizeof(struct file), ZONE_NORMAL);
-	if (!file)
-		return ERR_PTR(-ENOMEM);
-
-	file->fs = fs;
-	file->buf = NULL;
-
 	memcpy(__fn, fn, 8);
 	memcpy(__ft, ft, 8);
 	ascii2ebcdic((u8 *) __fn, 8);
@@ -88,43 +154,39 @@
 	mutex_lock(&fs->lock);
 
 	/* first, check the cache */
-	list_for_each_entry(tmpf, &fs->files, files) {
-		if (!memcmp((char*) tmpf->FST.FSTFNAME, __fn, 8) &&
-		    !memcmp((char*) tmpf->FST.FSTFTYPE, __ft, 8)) {
+	list_for_each_entry(file, &fs->files, files) {
+		if (!memcmp((char*) file->FST.FNAME, __fn, 8) &&
+		    !memcmp((char*) file->FST.FTYPE, __ft, 8)) {
 			mutex_unlock(&fs->lock);
-			free(file);
-			return tmpf;
+			return file;
 		}
 	}
 
-	page = alloc_pages(0, ZONE_NORMAL);
-	if (!page) {
-		ret = -ENOMEM;
-		goto out_unlock;
+	/* the slow path */
+	file = __alloc_file(fs, NULL);
+	if (IS_ERR(file)) {
+		ret = PTR_ERR(file);
+		goto out;
 	}
-	file->buf = page_to_addr(page);
 
-	/* oh well, must do it the hard way ... read from disk */
-	ret = bdev_read_block(fs->dev, fs->tmp_buf, fs->ADT.ADTDOP);
-	if (ret)
-		goto out_unlock;
-
-	fst = fs->tmp_buf;
+	for(blk=0; blk<fs->dir->FST.ADBC; blk++) {
+		fst = bcache_read(fs->dir, 0, blk);
+		if (IS_ERR(fst))
+			goto out_free;
 
-	for(i=0,found=0; i<fs->ADT.ADTNFST; i++) {
-		if ((!memcmp(fst[i].FSTFNAME, __fn, 8)) &&
-		    (!memcmp(fst[i].FSTFTYPE, __ft, 8))) {
-			memcpy(&file->FST, &fst[i], sizeof(struct FST));
-			found = 1;
-			break;
+		for(i=0; i<fs->ADT.NFST; i++) {
+			if ((!memcmp(fst[i].FNAME, __fn, 8)) &&
+			    (!memcmp(fst[i].FTYPE, __ft, 8))) {
+				memcpy(&file->FST, &fst[i], sizeof(struct FST));
+				goto found;
+			}
 		}
 	}
 
-	if (!found) {
-		ret = -ENOENT;
-		goto out_unlock;
-	}
+	ret = -ENOENT;
+	goto out_free;
 
+found:
 	mutex_init(&file->lock, &edf_file);
 	list_add_tail(&file->files, &fs->files);
 
@@ -132,36 +194,43 @@
 
 	return file;
 
-out_unlock:
-	if (file && file->buf)
-		free_pages(file->buf, 0);
+out_free:
+	__free_file(file);
+
+out:
 	mutex_unlock(&fs->lock);
-	free(file);
 	return ERR_PTR(ret);
 }
 
 int edf_read_rec(struct file *file, char *buf, u32 recno)
 {
 	struct fs *fs = file->fs;
-	u32 fop, lrecl;
-	int ret;
-
-	if (file->FST.FSTNLVL != 0 ||
-	    file->FST.FSTPTRSZ != 4 ||
-	    file->FST.FSTLRECL > fs->ADT.ADTDBSIZ ||
-	    file->FST.FSTRECFM != FSTDFIX)
-		return -EINVAL;
+	u32 blk, off;
+	char *dbuf;
+	int ret = -EINVAL;
 
 	mutex_lock(&file->lock);
 
-	fop = file->FST.FSTFOP;
-	lrecl = file->FST.FSTLRECL;
-
-	ret = bdev_read_block(fs->dev, file->buf, fop);
-	if (ret)
+	if (file->FST.NLVL != 0 ||
+	    file->FST.PTRSZ != 4 ||
+	    file->FST.LRECL > fs->ADT.DBSIZ ||
+	    file->FST.RECFM != FSTDFIX)
 		goto out;
 
-	memcpy(buf, file->buf + (recno * lrecl), lrecl);
+	blk = (recno * file->FST.LRECL) / fs->ADT.DBSIZ;
+	off = (recno * file->FST.LRECL) % fs->ADT.DBSIZ;
+
+	dbuf = bcache_read(file, 0, blk);
+	if (IS_ERR(dbuf)) {
+		ret = PTR_ERR(dbuf);
+		goto out;
+	}
+
+	BUG_ON((off + file->FST.LRECL) > fs->ADT.DBSIZ);
+
+	memcpy(buf, dbuf + off, file->FST.LRECL);
+
+	ret = 0;
 
 out:
 	mutex_unlock(&file->lock);
@@ -174,8 +243,6 @@
 	struct fs *fs = file->fs;
 
 	mutex_lock(&fs->lock);
-	list_del(&file->files);
+	__free_file(file);
 	mutex_unlock(&fs->lock);
-
-	free(file);
 }
--- a/cp/include/edf.h	Mon Apr 25 09:15:18 2011 -0400
+++ b/cp/include/edf.h	Mon Apr 25 09:15:29 2011 -0400
@@ -12,45 +12,45 @@
 #include <device.h>
 
 struct ADT {
-	u32     ADTIDENT;       /* VOL START / LABEL IDENTIFIER */
+	u32     IDENT;       /* VOL START / LABEL IDENTIFIER */
 #define __ADTIDENT 0xC3D4E2F1   /* 'CMS1' in EBCDIC */
-	u8      ADTID[6];       /* VOL START / VOL IDENTIFIER */
-	u8      ADTVER[2];      /* VERSION LEVEL */
-	u32     ADTDBSIZ;       /* DISK BLOCK SIZE */
-	u32     ADTDOP;         /* DISK ORIGIN POINTER */
-	u32     ADTCYL;         /* NUM OF FORMATTED CYL ON DISK */
-	u32     ADTMCYL;        /* MAX NUM FORMATTED CYL ON DISK */
-	u32     ADTNUM;         /* Number of Blocks on disk */
-	u32     ADTUSED;        /* Number of Blocks used */
-	u32     ADTFSTSZ;       /* SIZE OF FST */
-	u32     ADTNFST;        /* NUMBER OF FST'S PER BLOCK */
-	u8      ADTDCRED[6];    /* DISK CREATION DATE (YYMMDDHHMMSS) */
-	u8      ADTFLGL;        /* LABEL FLAG BYTE (ADTFLGL) */
+	u8      ID[6];       /* VOL START / VOL IDENTIFIER */
+	u8      VER[2];      /* VERSION LEVEL */
+	u32     DBSIZ;       /* DISK BLOCK SIZE */
+	u32     DOP;         /* DISK ORIGIN POINTER */
+	u32     CYL;         /* NUM OF FORMATTED CYL ON DISK */
+	u32     MCYL;        /* MAX NUM FORMATTED CYL ON DISK */
+	u32     NUM;         /* Number of Blocks on disk */
+	u32     USED;        /* Number of Blocks used */
+	u32     FSTSZ;       /* SIZE OF FST */
+	u32     NFST;        /* NUMBER OF FST'S PER BLOCK */
+	u8      DCRED[6];    /* DISK CREATION DATE (YYMMDDHHMMSS) */
+	u8      FLGL;        /* LABEL FLAG BYTE (ADTFLGL) */
 #define ADTCNTRY        0x01    /* Century for disk creation date (0=19, 1=20),
 	                         * corresponds to ADTDCRED. */
 	u8      reserved[1];
-	u32     ADTOFFST;       /* DISK OFFSET WHEN RESERVED */
-	u32     ADTAMNB;        /* ALLOC MAP BLOCK WITH NEXT HOLE */
-	u32     ADTAMND;        /* DISP INTO HBLK DATA OF NEXT HOLE */
-	u32     ADTAMUP;        /* DISP INTO USER PART OF ALLOC MAP */
-	u32     ADTOFCNT;       /* Count of SFS open files for this ADT */
-	u8      ADTSFNAM[8];    /* NAME OF SHARED SEGMENT */
+	u32     OFFST;       /* DISK OFFSET WHEN RESERVED */
+	u32     AMNB;        /* ALLOC MAP BLOCK WITH NEXT HOLE */
+	u32     AMND;        /* DISP INTO HBLK DATA OF NEXT HOLE */
+	u32     AMUP;        /* DISP INTO USER PART OF ALLOC MAP */
+	u32     OFCNT;       /* Count of SFS open files for this ADT */
+	u8      SFNAM[8];    /* NAME OF SHARED SEGMENT */
 };
 
 struct FST {
-	u8    FSTFNAME[8];       /* filename */
-	u8    FSTFTYPE[8];       /* filetype */
-	u8    FSTDATEW[2];       /* DATE LAST WRITTEN - MMDD */
-	u8    FSTTIMEW[2];       /* TIME LAST WRITTEN - HHMM */
-	u16   FSTWRPNT;          /* WRITE POINTER - ITEM NUMBER */
-	u16   FSTRDPNT;          /* READ POINTER - ITEM NUMBER */
-	u8    FSTFMODE[2];       /* FILE MODE - LETTER AND NUMBER */
-	u16   FSTRECCT;          /* NUMBER OF LOGICAL RECORDS */
-	u16   FSTFCLPT;          /* FIRST CHAIN LINK POINTER */
-	u8    FSTRECFM;          /* F*1 - RECORD FORMAT - F OR V */
+	u8    FNAME[8];       /* filename */
+	u8    FTYPE[8];       /* filetype */
+	u8    DATEW[2];       /* DATE LAST WRITTEN - MMDD */
+	u8    TIMEW[2];       /* TIME LAST WRITTEN - HHMM */
+	u16   WRPNT;          /* WRITE POINTER - ITEM NUMBER */
+	u16   RDPNT;          /* READ POINTER - ITEM NUMBER */
+	u8    FMODE[2];       /* FILE MODE - LETTER AND NUMBER */
+	u16   RECCT;          /* NUMBER OF LOGICAL RECORDS */
+	u16   FCLPT;          /* FIRST CHAIN LINK POINTER */
+	u8    RECFM;          /* 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 */
+	u8    FLAGS;          /* F*2 - FST FLAG BYTE */
 #define FSTRWDSK       0x80 /* READ/WRITE DISK */
 #define FSTRODSK       0x00 /* READ/ONLY DISK */
 #define FSTDSFS        0x10 /* Shared File FST */
@@ -65,17 +65,17 @@
 #define FSTACTWR       0x02 /* ACTIVE FOR WRITING */
 #define FSTACTPT       0x01 /* ACTIVE FROM A POINT */
 #define FSTFILEA       0x07 /* THE FILE IS ACTIVE */
-	u32   FSTLRECL;          /* LOGICAL RECORD LENGTH */
-	u16   FSTBLKCT;          /* NUMBER OF 800 BYTE BLOCKS */
-	u16   FSTYEARW;          /* YEAR LAST WRITTEN */
-	u32   FSTFOP;            /* ALT. FILE ORIGIN POINTER */
-	u32   FSTADBC;           /* ALT. NUMBER OF DATA BLOCKS */
-	u32   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 */
+	u32   LRECL;          /* LOGICAL RECORD LENGTH */
+	u16   BLKCT;          /* NUMBER OF 800 BYTE BLOCKS */
+	u16   YEARW;          /* YEAR LAST WRITTEN */
+	u32   FOP;            /* ALT. FILE ORIGIN POINTER */
+	u32   ADBC;           /* ALT. NUMBER OF DATA BLOCKS */
+	u32   AIC;            /* ALT. ITEM COUNT */
+	u8    NLVL;           /* NUMBER OF POINTER BLOCK LEVELS */
+	u8    PTRSZ;          /* LENGTH OF A POINTER ELEMENT */
+	u8    ADATI[6];       /* ALT. DATE/TIME(YY MM DD HH MM SS) */
+	u8    REALM;          /* Real filemode */
+	u8    FLAG2;          /* F*3 - FST FLAG BYTE 2 FSTFLAG2 */
 #define FSTPIPEU       0x10 /* Reserved for CMS PIPELINES usage */
 	u8    reserved[2];
 };
@@ -84,20 +84,27 @@
 
 #define EDF_SUPPORTED_BLOCK_SIZE	4096
 
+#define DIRECTOR_FN	((u8*) "\x00\x00\x00\x01\x00\x00\x00\x00")
+#define DIRECTOR_FT	((u8*) "\xc4\xc9\xd9\xc5\xc3\xe3\xd6\xd9")
+#define ALLOCMAP_FN	((u8*) "\x00\x00\x00\x02\x00\x00\x00\x00")
+#define ALLOCMAP_FT	((u8*) "\xc1\xd3\xd3\xd6\xc3\xd4\xc1\xd7")
+
+struct file;
+
 struct fs {
 	struct ADT ADT;
 	struct list_head files;
 	mutex_t lock;
 	struct device *dev;
-	void *tmp_buf;
+	struct file *dir;
 };
 
 struct file {
 	struct FST FST;
-	struct list_head files;
+	struct list_head files; /* fs->files */
+	struct list_head bcache;
 	mutex_t lock;
 	struct fs *fs;
-	char *buf;
 };
 
 extern struct fs *edf_mount(struct device *dev);
--- a/cp/nucleus/config.c	Mon Apr 25 09:15:18 2011 -0400
+++ b/cp/nucleus/config.c	Mon Apr 25 09:15:29 2011 -0400
@@ -176,7 +176,7 @@
 		return PTR_ERR(file);
 
 	/* parse each record in the config file */
-	for(i=0; i<file->FST.FSTAIC; i++) {
+	for(i=0; i<file->FST.AIC; i++) {
 		ret = edf_read_rec(file, buf, i);
 		if (ret)
 			return ret;