Block layer and ext2 headers
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 1 Sep 2010 00:41:00 +0000 (17:41 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:53 +0000 (17:35 -0700)
This adds a non-blocking block layer, suitably only for ramdisks
(make_request() just does the block driver part).  This also adds the
first ext2 bits.  It'll look for an image file formatted with ext2 (no
disk partitions or anything.  Or cells).

Makeconfig
Makelocal.template
kern/include/blockdev.h [new file with mode: 0644]
kern/include/devfs.h
kern/include/ext2fs.h [new file with mode: 0644]
kern/include/vfs.h
kern/src/Makefrag
kern/src/blockdev.c [new file with mode: 0644]
kern/src/devfs.c
kern/src/init.c
kern/src/vfs.c

index c528324..6916413 100644 (file)
@@ -9,6 +9,7 @@ CONFIG_APPSERVER:=                 -D__CONFIG_APPSERVER__
 # To enable any of these options, add a line like the following to your Makelocal
 # KERN_CFLAGS += $(CONFIG_KFS) $(CONFIG_BSD_ON_CORE0)
 CONFIG_KFS:=                       -D__CONFIG_KFS__
+CONFIG_KFS:=                       -D__CONFIG_EXT2FS__
 CONFIG_DEDICATED_MONITOR:=         -D__CONFIG_DEDICATED_MONITOR__
 CONFIG_SINGLE_CORE:=               -D__CONFIG_SINGLE_CORE__
 CONFIG_NETWORKING:=                -D__CONFIG_NETWORKING__
index bd14c95..01937e0 100644 (file)
@@ -3,6 +3,7 @@
 
 # Kernel configuration parameters
 #KERN_CFLAGS += $(CONFIG_KFS)
+#KERN_CFLAGS += $(CONFIG_EXT2FS)
 #KERN_CFLAGS += $(CONFIG_DEDICATED_MONITOR)
 #KERN_CFLAGS += $(CONFIG_SINGLE_CORE)
 #KERN_CFLAGS += $(CONFIG_NETWORKING)
@@ -32,6 +33,8 @@
 #INITRAMFS_PATHS = kern/kfs obj/tests
 # Program to execute before building the initramfs
 #INITRAMFS_BIN = tools/whatever.sh
+# Image for ext2 (RAM version) (only brho uses this )
+#EXT2_BDEV = mnt/ext2fs.img
 
 # Userspace configuration parameters
 #USER_CFLAGS += $(CONFIG_SYSCALL_TRAP)
diff --git a/kern/include/blockdev.h b/kern/include/blockdev.h
new file mode 100644 (file)
index 0000000..f0af33c
--- /dev/null
@@ -0,0 +1,61 @@
+/* Copyright (c) 2010 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Block device interfaces and structures */
+
+#ifndef ROS_KERN_BLOCKDEV_H
+#define ROS_KERN_BLOCKDEV_H
+
+#include <ros/common.h>
+#include <kref.h>
+#include <slab.h>
+
+/* All block IO is done assuming a certain size sector, which is the smallest
+ * possible unit of transfer between the kernel and the block layer.  This can
+ * be bigger than what the underlying hardware can handle, but it shouldn't be
+ * smaller than any higher-level block (like an FS block, which are often 1 KB).
+ */
+#define SECTOR_SIZE 512
+
+/* Every block device is represented by one of these, with custom methods, as
+ * applicable for the type of device.  Subject to massive changes. */
+#define BDEV_INLINE_NAME 10
+struct block_device {
+       int                                                     b_id;
+       unsigned int                            b_sector_size;          /* HW sector size */
+       unsigned int                            b_num_sectors;          /* Total sectors on dev */
+       struct kref                                     b_kref;
+       void                                            *b_data;                        /* dev-specific use */
+       char                                            b_name[BDEV_INLINE_NAME];
+       // TODO: list or something of buffer heads (?)
+       // list of outstanding requests
+       // io scheduler
+       // callbacks for completion
+};
+
+/* This encapsulates the work of a request (instead of having a variety of
+ * slightly-different functions for things like read/write and scatter-gather
+ * ops).  Reads and writes are essentially the same, so all we need is a flag to
+ * differentiate.  This struct also serves as a tool to track the progress of a
+ * block request throughout its servicing.  This is analagous to Linux's struct
+ * bio.
+ *
+ * For now, this just holds the stuff to do some simple sector reading. */
+struct block_request {
+       int                                                     flags;
+       void                                            *buffer;
+       unsigned int                            first_sector;
+       unsigned int                            amount;
+};
+struct kmem_cache *breq_kcache;        /* for the block requests */
+
+/* Block request flags */
+#define BREQ_READ                      0x001
+#define BREQ_WRITE                     0x002
+
+void block_init(void);
+/* This function will probably be the one that blocks */
+int make_request(struct block_device *bdev, struct block_request *req);
+
+#endif /* ROS_KERN_BLOCKDEV_H */
index 6979fc5..825197e 100644 (file)
@@ -9,10 +9,18 @@
 #define ROS_KERN_DEVFS_H
 
 #include <vfs.h>
+#include <kfs.h>
 
 void devfs_init(void);
+struct file *make_device(char *path, int mode, int type,
+                         struct file_operations *fop);
 
-/* Exporting these for convenience */
+/* Generic device (block or char) file ops.  Both of these are dummies that say
+ * the device can't support the operation. */
+int dev_mmap(struct file *file, struct vm_region *vmr);
+off_t dev_c_llseek(struct file *file, off_t offset, int whence);
+
+/* Exporting these for convenience (process creation) */
 extern struct file *dev_stdin, *dev_stdout, *dev_stderr;
 
 #endif /* !ROS_KERN_DEVFS_H */
diff --git a/kern/include/ext2fs.h b/kern/include/ext2fs.h
new file mode 100644 (file)
index 0000000..0b56757
--- /dev/null
@@ -0,0 +1,246 @@
+/* Copyright (c) 2010 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * The ROS port for Ext2 FS.  Thanks to Dave Poirier for maintaining this great
+ * documentation: http://www.nongnu.org/ext2-doc/ext2.html and the ext group
+ * that wrote the FS in the first place.
+ *
+ * Note all of ext2's disk structures are little-endian. */
+
+#ifndef ROS_KERN_EXT2FS_H
+#define ROS_KERN_EXT2FS_H
+
+#include <ros/common.h>
+#include <vfs.h>
+#include <endian.h>
+
+#define EXT2_SUPER_MAGIC               0xef53
+
+/* State settings */
+#define EXT2_VALID_FS                  1               /* Cleanly unmounted */
+#define EXT2_ERROR_FS                  2               /* Currently mounted / not unmounted */
+
+/* s_error options */
+#define EXT2_ERRORS_CONTINUE   1               /* continue on error */
+#define EXT2_ERRORS_RO                 2               /* remount read-only */
+#define EXT2_ERRORS_PANIC              3               /* panic on error */
+
+/* Creator OS options */
+#define EXT2_OS_LINUX                  0
+#define EXT2_OS_HURD                   1
+#define EXT2_OS_MASIX                  2
+#define EXT2_OS_FREEBSD                        3
+#define EXT2_OS_LITES                  4
+#define EXT2_OS_ROS                            666             /* got dibs on the mark of the beast */
+
+/* Revision Levels */
+#define EXT2_GOOD_OLD_REV              0               /* Revision 0 */
+#define EXT2_DYNAMIC_REV               1               /* Revision 1, extra crazies, etc */
+
+/* FS Compatibile Features.  We can support them or now, without risk of
+ * damaging meta-data. */
+#define EXT2_FEATURE_COMPAT_DIR_PREALLOC       0x0001  /* block prealloc */
+#define EXT2_FEATURE_COMPAT_MAGIC_INODES       0x0002
+#define EXT2_FEATURE_COMPAT_HAS_JOURNAL                0x0004  /* ext3/4 journal */
+#define EXT2_FEATURE_COMPAT_EXT_ATTR           0x0008  /* extended inode attr */
+#define EXT2_FEATURE_COMPAT_RESIZE_INO         0x0010  /* non-standard ino size */
+#define EXT2_FEATURE_COMPAT_DIR_INDEX          0x0020  /* h-tree dir indexing */
+
+/* FS Incompatibile Features.  We should refuse to mount if we don't support
+ * any of these. */
+#define EXT2_FEATURE_INCOMPAT_COMPRESSION      0x0001  /* disk compression */
+#define EXT2_FEATURE_INCOMPAT_FILETYPE         0x0002
+#define EXT2_FEATURE_INCOMPAT_RECOVER          0x0004
+#define EXT2_FEATURE_INCOMPAT_JOURNAL_DEV      0x0008
+#define EXT2_FEATURE_INCOMPAT_META_BG          0x0010
+
+/* FS read-only features: We should mount read-only if we don't support these */
+#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER    0x0001  /* sparse superblock */
+#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE      0x0002  /* 64-bit filesize */
+#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR       0x0004  /* binary tree sorted dir */
+
+/* Compression types (s_algo_bitmap) */
+#define EXT2_LZV1_ALG                  0x0001
+#define EXT2_LZRW3A_ALG                        0x0002
+#define EXT2_GZIP_ALG                  0x0004
+#define EXT2_BZIP2_ALG                 0x0008
+#define EXT2_LZO_ALG                   0x0010
+
+/* Defined Reserved inodes */
+#define EXT2_BAD_INO                   1               /* bad blocks inode */
+#define EXT2_ROOT_INO                  2               /* root directory inode */
+#define EXT2_ACL_IDX_INO               3               /* ACL index (deprecated?) */
+#define EXT2_ACL_DATA_INO              4               /* ACL data (deprecated?) */
+#define EXT2_BOOT_LOADER_INO   5               /* boot loader inode */
+#define EXT2_UNDEL_DIR_INO             6               /* undelete directory inode */
+
+/* Inode/File access mode and type (i_mode).  Note how they use hex here, but
+the crap we keep around for glibc/posix is (probably still) in octal. */
+#define EXT2_S_IFSOCK                  0xC000  /* socket */
+#define EXT2_S_IFLNK                   0xA000  /* symbolic link */
+#define EXT2_S_IFREG                   0x8000  /* regular file */
+#define EXT2_S_IFBLK                   0x6000  /* block device */
+#define EXT2_S_IFDIR                   0x4000  /* directory */
+#define EXT2_S_IFCHR                   0x2000  /* character device */
+#define EXT2_S_IFIFO                   0x1000  /* fifo */
+#define EXT2_S_ISUID                   0x0800  /* set process user id */
+#define EXT2_S_ISGID                   0x0400  /* set process group id */
+#define EXT2_S_ISVTX                   0x0200  /* sticky bit */
+#define EXT2_S_IRUSR                   0x0100  /* user read */
+#define EXT2_S_IWUSR                   0x0080  /* user write */
+#define EXT2_S_IXUSR                   0x0040  /* user execute */
+#define EXT2_S_IRGRP                   0x0020  /* group read */
+#define EXT2_S_IWGRP                   0x0010  /* group write */
+#define EXT2_S_IXGRP                   0x0008  /* group execute */
+#define EXT2_S_IROTH                   0x0004  /* others read */
+#define EXT2_S_IWOTH                   0x0002  /* others write */
+#define EXT2_S_IXOTH                   0x0001  /* others execute */
+
+/* Inode flags, for how to access data for an inode/file/object */
+#define EXT2_SECRM_FL                  0x00000001      /* secure deletion */
+#define EXT2_UNRM_FL                   0x00000002      /* record for undelete */
+#define EXT2_COMPR_FL                  0x00000004      /* compressed file */
+#define EXT2_SYNC_FL                   0x00000008      /* synchronous updates */
+#define EXT2_IMMUTABLE_FL              0x00000010      /* immutable file */
+#define EXT2_APPEND_FL                 0x00000020      /* append only */
+#define EXT2_NODUMP_FL                 0x00000040      /* do not dump/delete file */
+#define EXT2_NOATIME_FL                        0x00000080      /* do not update i_atime */
+/* Compression Flags */
+#define EXT2_DIRTY_FL                  0x00000100      /* dirty (modified) */
+#define EXT2_COMPRBLK_FL               0x00000200      /* compressed blocks */
+#define EXT2_NOCOMPR_FL                        0x00000400      /* access raw compressed data */
+#define EXT2_ECOMPR_FL                 0x00000800      /* compression error */
+/* End of compression flags */
+#define EXT2_BTREE_FL                  0x00010000      /* b-tree format directory */
+#define EXT2_INDEX_FL                  0x00010000      /* hash indexed directory */
+#define EXT2_IMAGIC_FL                 0x00020000      /* AFS directory */
+#define EXT3_JOURNAL_DATA_FL   0x00040000      /* journal file data */
+#define EXT2_RESERVED_FL               0x80000000      /* reserved for ext2 library */
+
+/* Directory entry file types */
+#define EXT2_FT_UNKNOWN                        0       /* unknown file type */
+#define EXT2_FT_REG_FILE               1       /* regular file */
+#define EXT2_FT_DIR                            2       /* directory */
+#define EXT2_FT_CHRDEV                 3       /* character device */
+#define EXT2_FT_BLKDEV                 4       /* block device */
+#define EXT2_FT_FIFO                   5       /* FIFO / buffer file */
+#define EXT2_FT_SOCK                   6       /* socket */
+#define EXT2_FT_SYMLINK                        7       /* symbolic link */
+
+struct ext2_sb {
+       uint32_t                                        s_inodes_cnt;           /* total, both used/free */
+       uint32_t                                        s_blocks_cnt;           /* used/free/reserved */
+       uint32_t                                        s_rblocks_cnt;          /* reserved for su/brho */
+       uint32_t                                        s_free_blocks_cnt;      /* free, incl reserved */
+       uint32_t                                        s_free_inodes_cnt;
+       uint32_t                                        s_first_data_block;     /* id of block holding sb */
+       uint32_t                                        s_log_block_size;
+       uint32_t                                        s_log_frag_size;        /* no real frag support */
+       uint32_t                                        s_blocks_per_group;
+       uint32_t                                        s_frags_per_group;
+       uint32_t                                        s_inodes_per_group;
+       uint32_t                                        s_mtime;                        /* last mount time */
+       uint32_t                                        s_wtime;                        /* last write to the FS */
+       uint16_t                                        s_mnt_cnt;                      /* mounts since fsck */
+       uint16_t                                        s_max_mnt_cnt;          /* mounts between fscks */
+       uint16_t                                        s_magic;
+       uint16_t                                        s_state;                        /* mount state */
+       uint16_t                                        s_errors;                       /* what to do on error */
+       uint16_t                                        s_minor_rev_level;
+       uint32_t                                        s_lastcheck;            /* last fsck */
+       uint32_t                                        s_checkinterval;        /* max time btw fscks */
+       uint32_t                                        s_creator_os;
+       uint32_t                                        s_rev_level;
+       uint16_t                                        s_def_resuid;           /* uid for reserved blocks*/
+       uint16_t                                        s_def_resgid;           /* gid for reserved blocks*/
+/* Next chunk, EXT2_DYNAMIC_REV specific */
+       uint32_t                                        s_first_ino;            /* first usable for F_REG */
+       uint16_t                                        s_inode_size;
+       uint16_t                                        s_block_group_nr;       /* BG holding *this* SB */
+       uint32_t                                        s_feature_compat;
+       uint32_t                                        s_feature_incompat;
+       uint32_t                                        s_feature_ro_compat;
+       uint64_t                                        s_uuid[2];                      /* volume id */
+       char                                            s_volume_name[16];      /* null terminated */
+       char                                            s_last_mounted[64];     /* dir path of mount */
+       uint32_t                                        s_algo_bitmap;          /* compression type */
+/* Next chunk, Performance Hints */
+       uint8_t                                         s_prealloc_blocks;      /* when making F_REG */
+       uint8_t                                         s_prealloc_dir_blocks;  /* when making F_DIR */
+       uint16_t                                        s_padding1;
+/* Next chunk, Journaling Support */
+       uint8_t                                         s_journal_uuid[16];
+       uint32_t                                        s_journal_inum;         /* ino of the journal file*/
+       uint32_t                                        s_journal_dev;          /* device num of journal */
+       uint32_t                                        s_last_orphan;          /* first in list to delete*/
+/* Next chunk, Directory Indexing Support */
+       uint32_t                                        s_hash_seed[4];         /* for directory indexing */
+       uint8_t                                         s_def_hash_version;     /* default */
+       uint8_t                                         s_padding2;
+       uint16_t                                        s_padding3;
+/* Next chunk, Other options */
+       uint32_t                                        s_default_mount_opts;
+       uint32_t                                        s_first_meta_bg;        /* BG id of first meta */
+       uint8_t                                         s_reserved[760];
+};
+
+/* All block ids are absolute (not relative to the BG). */
+struct ext2_block_group {
+       uint32_t                                        bg_block_bitmap;        /* block id of bitmap */
+       uint32_t                                        bg_inode_bitmap;        /* block id of bitmap */
+       uint32_t                                        bg_inode_table;         /* id of first block */
+       uint16_t                                        bg_free_blocks_cnt;
+       uint16_t                                        bg_free_inodes_cnt;
+       uint16_t                                        bg_used_dirs_cnt;       /* inodes alloc to dirs */
+       uint16_t                                        bg_padding;
+       uint8_t                                         bg_reserved[12];
+};
+
+/* Random note: expect some number of the initial inodes to be reserved (11 in
+ * rev 0), and later versions just start from s_first_ino.
+ *
+ * Only regular files use the full 32bits of size.  Rev 0 uses a signed i_size.
+ *
+ * For the i_blocks, the first 12 are block numbers for direct blocks.  The
+ * 13th entry ([12]) is the block number for the first indirect block.  The
+ * 14th entry is the number for a doubly-indirect block, and the 15th is a
+ * triply indirect block. Having a value of 0 in the array terminates it, with
+ * no further blocks. (not clear how that works with holes)
+ *
+ * For the osd2[12], these should be unused for ext2, and they should be used
+ * differently for ext4.
+ *
+ * Giant warning: the inode numbers start at 1 in the system, not 0! */
+struct ext2_inode {
+       uint16_t                                        i_mode;                         /* file type and mode */
+       uint16_t                                        i_uid;
+       uint32_t                                        i_size;                         /* lower 32bits of size */
+       uint32_t                                        i_atime;
+       uint32_t                                        i_ctime;
+       uint32_t                                        i_mtime;
+       uint32_t                                        i_dtime;                        /* delete time */
+       uint16_t                                        i_gid;
+       uint16_t                                        i_links_cnt;            /* fs_ino->i_nlinks */
+       uint32_t                                        i_blocks;                       /* num blocks reserved */
+       uint32_t                                        i_flags;                        /* how to access data */
+       uint32_t                                        i_osd1;                         /* OS dependent */
+       uint32_t                                        i_block[15];            /* list of blocks reserved*/
+       uint32_t                                        i_generation;           /* used by NFS */
+       uint32_t                                        i_file_acl;                     /* block num hold ext attr*/
+       uint32_t                                        i_dir_acl;                      /* upper 32bits of size */
+       uint32_t                                        i_faddr;                        /* fragment, obsolete. */
+       uint8_t                                         i_osd2[12];                     /* OS dependent */
+};
+
+/* a dir_inode of 0 means an unused entry.  reclen will go to the end of the
+ * data block when it is the last entry.  These are 4-byte aligned on disk. */
+struct ext2_dirent {
+       uint32_t                                        dir_inode;                      /* inode */
+       uint16_t                                        dir_reclen;                     /* len, including padding */
+       uint8_t                                         dir_namelen;            /* len of dir_name */
+       uint8_t                                         dir_filetype;
+       uint8_t                                         dir_name[256];          /* might be < 255 on disc */
+};
+
+#endif /* ROS_KERN_EXT2FS_H */
index c0ee51f..f42f686 100644 (file)
@@ -19,6 +19,7 @@
 #include <kref.h>
 #include <timing.h>
 #include <radix.h>
+#include <blockdev.h>
 
 /* ghetto preprocessor hacks (since proc includes vfs) */
 struct page;
@@ -29,7 +30,6 @@ typedef int dev_t;
 typedef int kdev_t;
 typedef int ino_t;
 typedef long off_t; // out there in other .h's, but not in the kernel yet
-struct block_device    {int x;};
 struct io_writeback    {int x;};
 struct event_poll {int x;};
 struct poll_table_struct {int x;};
index 3efbbb4..458a305 100644 (file)
@@ -44,6 +44,7 @@ KERN_SRCFILES := $(KERN_ARCH_SRCFILES) \
                  $(KERN_SRC_DIR)/radix.c \
                  $(KERN_SRC_DIR)/umem.c \
                  $(KERN_SRC_DIR)/devfs.c \
+                 $(KERN_SRC_DIR)/blockdev.c \
                  $(KERN_SRC_DIR)/testing.c \
                  $(KERN_SRC_DIR)/arsc.c
 
@@ -94,7 +95,8 @@ $(OBJDIR)/$(KERN_DIR)/%.o: $(KERN_DIR)/%.S
 $(OBJDIR)/$(KERN_DIR)/kernel: $(KERN_LDDEPENDS)
        @echo + ld [KERN] $@
        $(V)$(LD) -o $@ $(KERN_LDFLAGS) $(KERN_OBJFILES) $(KERN_LDLIBS) \
-                       $(KERN_GCC_LIB) -b binary $(OBJDIR)/$(KERN_DIR)/$(KERN_CPIO)
+                       $(KERN_GCC_LIB) -b binary $(OBJDIR)/$(KERN_DIR)/$(KERN_CPIO) \
+                       $(EXT2_BDEV)
        $(V)$(OBJDUMP) -S $@ > $@.asm
        $(V)$(NM) -n $@ > $@.sym
 
diff --git a/kern/src/blockdev.c b/kern/src/blockdev.c
new file mode 100644 (file)
index 0000000..e5e7e6b
--- /dev/null
@@ -0,0 +1,74 @@
+/* Copyright (c) 2010 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Block devices and generic blockdev infrastructure */
+
+#include <devfs.h>
+#include <blockdev.h>
+#include <kmalloc.h>
+#include <slab.h>
+
+struct file_operations block_f_op;
+struct kmem_cache *breq_kcache;
+
+void block_init(void)
+{
+       breq_kcache = kmem_cache_create("block_reqs", sizeof(struct block_request),
+                                       __alignof__(struct block_request), 0, 0, 0);
+
+       #ifdef __CONFIG_EXT2FS__
+       /* Now probe for and init the block device for the ext2 ram disk */
+       extern uint8_t _binary_mnt_ext2fs_img_size[];
+       extern uint8_t _binary_mnt_ext2fs_img_start[];
+       /* Build and init the block device */
+       struct block_device *ram_bd = kmalloc(sizeof(struct block_device), 0);
+       memset(ram_bd, 0, sizeof(struct block_device));
+       ram_bd->b_id = 31337;
+       ram_bd->b_sector_size = 512;
+       ram_bd->b_num_sectors = (unsigned int)_binary_mnt_ext2fs_img_size / 512;
+       kref_init(&ram_bd->b_kref, fake_release, 1);
+       ram_bd->b_data = _binary_mnt_ext2fs_img_start;
+       strncpy(ram_bd->b_name, "RAMDISK", BDEV_INLINE_NAME);
+       ram_bd->b_name[BDEV_INLINE_NAME - 1] = '\0';
+       /* Connect it to the file system */
+       struct file *ram_bf = make_device("/dev/ramdisk", S_IRUSR | S_IWUSR,
+                                         __S_IFBLK, &block_f_op);
+       ram_bf->f_dentry->d_inode->i_bdev = ram_bd;     /* this holds the bd kref */
+       kref_put(&ram_bf->f_kref);
+       #endif /* __CONFIG_EXT2FS__ */
+}
+
+int make_request(struct block_device *bdev, struct block_request *req)
+{
+       /* Sectors are indexed starting with 0, for now. */
+       if (req->first_sector + req->amount > bdev->b_num_sectors)
+               return -1;
+       if (req->flags & BREQ_READ)
+               memcpy(req->buffer, bdev->b_data + req->first_sector * SECTOR_SIZE,
+                      req->amount * SECTOR_SIZE);
+       else if (req->flags & BREQ_WRITE)
+               memcpy(bdev->b_data + req->first_sector * SECTOR_SIZE, req->buffer,
+                      req->amount * SECTOR_SIZE);
+       else
+               panic("Need a request type!\n");
+       return 0;
+}
+
+/* Block device file ops: for now, we don't let you do much of anything */
+struct file_operations block_f_op = {
+       dev_c_llseek,
+       0,
+       0,
+       kfs_readdir,    /* this will fail gracefully */
+       dev_mmap,
+       kfs_open,
+       kfs_flush,
+       kfs_release,
+       0,      /* fsync - makes no sense */
+       kfs_poll,
+       0,      /* readv */
+       0,      /* writev */
+       kfs_sendpage,
+       kfs_check_flags,
+};
index 391cd01..5f0f2f7 100644 (file)
@@ -21,19 +21,6 @@ struct file_operations dev_f_op_stdout;
 
 struct file *dev_stdin, *dev_stdout, *dev_stderr;
 
-/* Helper to build stdin, stdout, and stderr */
-static struct file *get_stdinout(char *name, int mode,
-                                 struct file_operations *fop)
-{
-       struct file *f_char_dev = do_file_open(name, O_CREAT, mode);
-       assert(f_char_dev);
-       /* Overwrite the f_op with our own f_ops */
-       f_char_dev->f_dentry->d_inode->i_fop = fop;
-       f_char_dev->f_op = fop;
-       SET_FTYPE(f_char_dev->f_dentry->d_inode->i_mode, __S_IFCHR);
-       return f_char_dev;
-}
-
 void devfs_init(void)
 {
        int mode;
@@ -45,17 +32,30 @@ void devfs_init(void)
                kref_put(&dentry->d_kref);
        }
        /* Notice we don't kref_put().  We're storing the refs globally */
-       dev_stdin = get_stdinout("/dev/stdin", S_IRUSR | S_IRGRP | S_IROTH,
-                                &dev_f_op_stdin);
-       dev_stdout = get_stdinout("/dev/stdout", S_IWUSR | S_IWGRP | S_IWOTH,
-                                 &dev_f_op_stdout);
+       dev_stdin = make_device("/dev/stdin", S_IRUSR | S_IRGRP | S_IROTH,
+                               __S_IFCHR, &dev_f_op_stdin);
+       dev_stdout = make_device("/dev/stdout", S_IWUSR | S_IWGRP | S_IWOTH,
+                                __S_IFCHR, &dev_f_op_stdout);
        /* Note stderr uses the same f_op as stdout */
-       dev_stderr = get_stdinout("/dev/stderr", S_IWUSR | S_IWGRP | S_IWOTH,
-                                 &dev_f_op_stdout);
+       dev_stderr = make_device("/dev/stderr", S_IWUSR | S_IWGRP | S_IWOTH,
+                                __S_IFCHR, &dev_f_op_stdout);
 }
 
-/* We provide a separate set of f_ops and pm_ops for devices (char for now), and
- * this is the only thing that differs from the regular KFS.  We need to do some
+/* Creates a device node at a given location in the FS-tree */
+struct file *make_device(char *path, int mode, int type,
+                         struct file_operations *fop)
+{
+       struct file *f_dev = do_file_open(path, O_CREAT, mode);
+       assert(f_dev);
+       /* Overwrite the f_op with our own f_ops */
+       f_dev->f_dentry->d_inode->i_fop = fop;
+       f_dev->f_op = fop;
+       SET_FTYPE(f_dev->f_dentry->d_inode->i_mode, type);
+       return f_dev;
+}
+
+/* We provide a separate set of f_ops for devices (char and block), and the fops
+ * is the only thing that differs from the regular KFS.  We need to do some
  * ghetto-overriding of these ops after we create them. */
 
 off_t dev_c_llseek(struct file *file, off_t offset, int whence)
@@ -64,6 +64,13 @@ off_t dev_c_llseek(struct file *file, off_t offset, int whence)
        return -1;
 }
 
+/* we don't allow mmapping of any device file */
+int dev_mmap(struct file *file, struct vm_region *vmr)
+{
+       set_errno(EINVAL);
+       return -1;
+}
+
 ssize_t dev_stdin_read(struct file *file, char *buf, size_t count,
                        off_t *offset)
 {
@@ -98,14 +105,7 @@ ssize_t dev_stdout_write(struct file *file, const char *buf, size_t count,
        return count;
 }
 
-/* we don't allow mmapping of any device file */
-int dev_mmap(struct file *file, struct vm_region *vmr)
-{
-       set_errno(EINVAL);
-       return -1;
-}
-
-/* Character device file ops */
+/* stdin/stdout/stderr file ops */
 struct file_operations dev_f_op_stdin = {
        dev_c_llseek,
        dev_stdin_read,
index c83bac2..9977b1e 100644 (file)
@@ -39,6 +39,7 @@
 #include <kfs.h>
 #include <vfs.h>
 #include <devfs.h>
+#include <blockdev.h>
 
 // zra: flag for Ivy
 int booting = 1;
@@ -91,6 +92,7 @@ void kernel_init(multiboot_info_t *mboot_info)
        
        // At this point our boot paths diverge based on arch. 
        arch_init();
+       block_init();
                
 //     printk("Starting tests....\n");
 //     test_color_alloc();
index 743413b..d1e7a01 100644 (file)
@@ -1760,6 +1760,10 @@ static void print_dir(struct dentry *dentry, char *buf, int depth)
                                        printk("%s%s (char device) nlink: %d\n", buf, next.d_name,
                                               child_d->d_inode->i_nlink);
                                        break;
+                               case (__S_IFBLK):
+                                       printk("%s%s (block device) nlink: %d\n", buf, next.d_name,
+                                              child_d->d_inode->i_nlink);
+                                       break;
                                default:
                                        warn("Look around you!  Unknown filetype!");
                        }