Buffer heads to track page mappings -> block num
[akaros.git] / kern / src / blockdev.c
1 /* Copyright (c) 2010 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * Block devices and generic blockdev infrastructure */
6
7 #include <devfs.h>
8 #include <blockdev.h>
9 #include <kmalloc.h>
10 #include <slab.h>
11 #include <page_alloc.h>
12
13 struct file_operations block_f_op;
14 struct kmem_cache *breq_kcache;
15
16 void block_init(void)
17 {
18         breq_kcache = kmem_cache_create("block_reqs", sizeof(struct block_request),
19                                         __alignof__(struct block_request), 0, 0, 0);
20         bh_kcache = kmem_cache_create("buffer_heads", sizeof(struct buffer_head),
21                                       __alignof__(struct buffer_head), 0, 0, 0);
22
23         #ifdef __CONFIG_EXT2FS__
24         /* Now probe for and init the block device for the ext2 ram disk */
25         extern uint8_t _binary_mnt_ext2fs_img_size[];
26         extern uint8_t _binary_mnt_ext2fs_img_start[];
27         /* Build and init the block device */
28         struct block_device *ram_bd = kmalloc(sizeof(struct block_device), 0);
29         memset(ram_bd, 0, sizeof(struct block_device));
30         ram_bd->b_id = 31337;
31         ram_bd->b_sector_size = 512;
32         ram_bd->b_num_sectors = (unsigned int)_binary_mnt_ext2fs_img_size / 512;
33         kref_init(&ram_bd->b_kref, fake_release, 1);
34         ram_bd->b_data = _binary_mnt_ext2fs_img_start;
35         strncpy(ram_bd->b_name, "RAMDISK", BDEV_INLINE_NAME);
36         ram_bd->b_name[BDEV_INLINE_NAME - 1] = '\0';
37         /* Connect it to the file system */
38         struct file *ram_bf = make_device("/dev/ramdisk", S_IRUSR | S_IWUSR,
39                                           __S_IFBLK, &block_f_op);
40         ram_bf->f_dentry->d_inode->i_bdev = ram_bd;     /* this holds the bd kref */
41         kref_put(&ram_bf->f_kref);
42         #endif /* __CONFIG_EXT2FS__ */
43 }
44
45 /* Generic helper, returns a kref'd reference out of principle. */
46 struct block_device *get_bdev(char *path)
47 {
48         struct block_device *bdev;
49         struct file *block_f;
50         block_f = do_file_open(path, O_RDWR, 0);
51         assert(block_f);
52         bdev = block_f->f_dentry->d_inode->i_bdev;
53         kref_get(&bdev->b_kref, 1);
54         kref_put(&block_f->f_kref);
55         return bdev;
56 }
57
58 /* Frees all the BHs associated with page.  There could be 0, to deal with one
59  * that wasn't UPTODATE.  Don't call this on a page that isn't a PG_BUFFER */
60 void free_bhs(struct page *page)
61 {
62         struct buffer_head *bh, *next;
63         assert(page->pg_flags & PG_BUFFER);
64         bh = (struct buffer_head*)page->pg_private;
65         while (bh) {
66                 next = bh->bh_next;
67                 bh->bh_next = 0;
68                 kmem_cache_free(bh_kcache, bh);
69                 bh = next;
70         }
71         page->pg_private = 0;           /* catch bugs */
72 }
73
74 /* This ultimately will handle the actual request processing, all the way down
75  * to the driver, and will deal with blocking.  For now, we just fulfill the
76  * request right away. */
77 int make_request(struct block_device *bdev, struct block_request *req)
78 {
79         void *src, *dst;
80         /* Sectors are indexed starting with 0, for now. */
81         if (req->first_sector + req->amount > bdev->b_num_sectors)
82                 return -1;
83         if (req->flags & BREQ_READ) {
84                 dst = req->buffer;
85                 src = bdev->b_data + (req->first_sector << SECTOR_SZ_LOG);
86         } else if (req->flags & BREQ_WRITE) {
87                 dst = bdev->b_data + (req->first_sector << SECTOR_SZ_LOG);
88                 src = req->buffer;
89         } else {
90                 panic("Need a request type!\n");
91         }
92         memcpy(dst, src, req->amount << SECTOR_SZ_LOG);
93         return 0;
94 }
95
96 /* Block device file ops: for now, we don't let you do much of anything */
97 struct file_operations block_f_op = {
98         dev_c_llseek,
99         0,
100         0,
101         kfs_readdir,    /* this will fail gracefully */
102         dev_mmap,
103         kfs_open,
104         kfs_flush,
105         kfs_release,
106         0,      /* fsync - makes no sense */
107         kfs_poll,
108         0,      /* readv */
109         0,      /* writev */
110         kfs_sendpage,
111         kfs_check_flags,
112 };