More thoroughly detect preemptions
[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 #include <pmap.h>
13 /* These two are needed for the fake interrupt */
14 #include <alarm.h>
15 #include <smp.h>
16
17 struct file_operations block_f_op;
18 struct page_map_operations block_pm_op;
19 struct kmem_cache *breq_kcache;
20
21 void block_init(void)
22 {
23         breq_kcache = kmem_cache_create("block_reqs", sizeof(struct block_request),
24                                         __alignof__(struct block_request), 0, 0, 0);
25         bh_kcache = kmem_cache_create("buffer_heads", sizeof(struct buffer_head),
26                                       __alignof__(struct buffer_head), 0, 0, 0);
27
28         #ifdef __CONFIG_EXT2FS__
29         /* Now probe for and init the block device for the ext2 ram disk */
30         extern uint8_t _binary_mnt_ext2fs_img_size[];
31         extern uint8_t _binary_mnt_ext2fs_img_start[];
32         /* Build and init the block device */
33         struct block_device *ram_bd = kmalloc(sizeof(struct block_device), 0);
34         memset(ram_bd, 0, sizeof(struct block_device));
35         ram_bd->b_id = 31337;
36         ram_bd->b_sector_sz = 512;
37         ram_bd->b_nr_sector = (unsigned int)_binary_mnt_ext2fs_img_size / 512;
38         kref_init(&ram_bd->b_kref, fake_release, 1);
39         pm_init(&ram_bd->b_pm, &block_pm_op, ram_bd);
40         ram_bd->b_data = _binary_mnt_ext2fs_img_start;
41         strncpy(ram_bd->b_name, "RAMDISK", BDEV_INLINE_NAME);
42         ram_bd->b_name[BDEV_INLINE_NAME - 1] = '\0';
43         /* Connect it to the file system */
44         struct file *ram_bf = make_device("/dev/ramdisk", S_IRUSR | S_IWUSR,
45                                           __S_IFBLK, &block_f_op);
46         /* make sure the inode tracks the right pm (not it's internal one) */
47         ram_bf->f_dentry->d_inode->i_mapping = &ram_bd->b_pm;
48         ram_bf->f_dentry->d_inode->i_bdev = ram_bd;     /* this holds the bd kref */
49         kref_put(&ram_bf->f_kref);
50         #endif /* __CONFIG_EXT2FS__ */
51 }
52
53 /* Generic helper, returns a kref'd reference out of principle. */
54 struct block_device *get_bdev(char *path)
55 {
56         struct block_device *bdev;
57         struct file *block_f;
58         block_f = do_file_open(path, O_RDWR, 0);
59         assert(block_f);
60         bdev = block_f->f_dentry->d_inode->i_bdev;
61         kref_get(&bdev->b_kref, 1);
62         kref_put(&block_f->f_kref);
63         return bdev;
64 }
65
66 /* Frees all the BHs associated with page.  There could be 0, to deal with one
67  * that wasn't UPTODATE.  Don't call this on a page that isn't a PG_BUFFER.
68  * Note, these are not a circular LL (for now). */
69 void free_bhs(struct page *page)
70 {
71         struct buffer_head *bh, *next;
72         assert(page->pg_flags & PG_BUFFER);
73         bh = (struct buffer_head*)page->pg_private;
74         while (bh) {
75                 next = bh->bh_next;
76                 bh->bh_next = 0;
77                 kmem_cache_free(bh_kcache, bh);
78                 bh = next;
79         }
80         page->pg_private = 0;           /* catch bugs */
81 }
82
83 /* This ultimately will handle the actual request processing, all the way down
84  * to the driver, and will deal with blocking.  For now, we just fulfill the
85  * request right away (RAM based block devs). */
86 int bdev_submit_request(struct block_device *bdev, struct block_request *breq)
87 {
88         void *src, *dst;
89         unsigned long first_sector;
90         unsigned int nr_sector;
91
92         for (int i = 0; i < breq->nr_bhs; i++) {
93                 first_sector = breq->bhs[i]->bh_sector;
94                 nr_sector = breq->bhs[i]->bh_nr_sector;
95                 /* Sectors are indexed starting with 0, for now. */
96                 if (first_sector + nr_sector > bdev->b_nr_sector) {
97                         warn("Exceeding the num sectors!");
98                         return -1;
99                 }
100                 if (breq->flags & BREQ_READ) {
101                         dst = breq->bhs[i]->bh_buffer;
102                         src = bdev->b_data + (first_sector << SECTOR_SZ_LOG);
103                 } else if (breq->flags & BREQ_WRITE) {
104                         dst = bdev->b_data + (first_sector << SECTOR_SZ_LOG);
105                         src = breq->bhs[i]->bh_buffer;
106                 } else {
107                         panic("Need a request type!\n");
108                 }
109                 memcpy(dst, src, nr_sector << SECTOR_SZ_LOG);
110         }
111 #ifdef __i386__         /* Sparc can't kthread yet */
112         /* Faking the device interrupt with an alarm */
113         void breq_handler(struct alarm_waiter *waiter)
114         {
115                 /* In the future, we'll need to figure out which breq this was in
116                  * response to */
117                 struct block_request *breq = (struct block_request*)waiter->data;
118                 if (breq->callback)
119                         breq->callback(breq);
120                 kfree(waiter);
121         }
122         struct timer_chain *tchain = &per_cpu_info[core_id()].tchain;
123         struct alarm_waiter *waiter = kmalloc(sizeof(struct alarm_waiter), 0);
124         init_awaiter(waiter, breq_handler);
125         /* Stitch things up, so we know how to find things later */
126         waiter->data = breq;
127         /* Set for 5ms. */
128         set_awaiter_rel(waiter, 5000);
129         set_alarm(tchain, waiter);
130 #else
131         if (breq->callback)
132                 breq->callback(breq);
133 #endif
134
135         return 0;
136 }
137
138 /* Helper method, unblocks someone blocked on sleep_on_breq(). */
139 void generic_breq_done(struct block_request *breq)
140 {
141 #ifdef __i386__         /* Sparc can't restart kthreads yet */
142         struct kthread *sleeper = __up_sem(&breq->sem, TRUE);
143         if (!sleeper) {
144                 /* This shouldn't happen anymore.  Let brho know if it does. */
145                 warn("[kernel] no one waiting on breq %08p", breq);
146                 return;
147         }
148         kthread_runnable(sleeper);
149 #else
150         breq->data = (void*)1;
151 #endif
152 }
153
154 /* Helper, pairs with generic_breq_done().  Note we sleep here on a semaphore
155  * instead of faking it with an alarm.  Ideally, this code will be the same even
156  * for real block devices (that don't fake things with timer interrupts). */
157 void sleep_on_breq(struct block_request *breq)
158 {
159         /* Since printk takes a while, this may make you lose the race */
160         printd("Sleeping on breq %08p\n", breq);
161         assert(irq_is_enabled());
162 #ifdef __i386__
163         sleep_on(&breq->sem);
164 #else
165         /* Sparc can't block yet (TODO).  This only works if the completion happened
166          * first (for now) */
167         assert(breq->data);
168 #endif
169 }
170
171 /* This just tells the page cache that it is 'up to date'.  Due to the nature of
172  * the blocks in the page cache, we don't actually read the items in on
173  * readpage, we read them in when a specific block is there */
174 int block_readpage(struct page_map *pm, struct page *page)
175 {
176         page->pg_flags |= PG_UPTODATE;
177         return 0;
178 }
179
180 /* Returns a BH pointing to the buffer where blk_num from bdev is located (given
181  * blocks of size blk_sz).  This uses the page cache for the page allocations
182  * and evictions, but only caches blocks that are requested.  Check the docs for
183  * more info.  The BH isn't refcounted, but a page refcnt is returned.  Call
184  * put_block (nand/xor dirty block).
185  *
186  * Note we're using the lock_page() to sync (which is what we do with the page
187  * cache too.  It's not ideal, but keeps things simpler for now.
188  *
189  * Also note we're a little inconsistent with the use of sector sizes in certain
190  * files.  We'll sort it eventually. */
191 struct buffer_head *bdev_get_buffer(struct block_device *bdev,
192                                     unsigned long blk_num, unsigned int blk_sz)
193 {
194         struct page *page;
195         struct page_map *pm = &bdev->b_pm;
196         struct buffer_head *bh, *new, *prev, **next_loc;
197         struct block_request *breq;
198         int error;
199         unsigned int blk_per_pg = PGSIZE / blk_sz;
200         unsigned int sct_per_blk = blk_sz / bdev->b_sector_sz;
201         unsigned int blk_offset = (blk_num % blk_per_pg) * blk_sz;
202         void *my_buf;
203         assert(blk_offset < PGSIZE);
204         if (!blk_num)
205                 warn("Asking for the 0th block of a bdev...");
206         /* Make sure there's a page in the page cache.  Should always be one. */
207         error = pm_load_page(pm, blk_num / blk_per_pg, &page); 
208         if (error)
209                 panic("Failed to load page! (%d)", error);
210         my_buf = page2kva(page) + blk_offset;
211         assert(page->pg_flags & PG_BUFFER);             /* Should be part of a page map */
212 retry:
213         bh = (struct buffer_head*)page->pg_private;
214         prev = 0;
215         /* look through all the BHs for ours, stopping if we go too far. */
216         while (bh) {
217                 if (bh->bh_buffer == my_buf) {
218                         goto found;
219                 } else if (bh->bh_buffer > my_buf) {
220                         break;
221                 }
222                 prev = bh;
223                 bh = bh->bh_next;
224         }
225         /* At this point, bh points to the one beyond our space (or 0), and prev is
226          * either the one before us or 0.  We make a BH, and try to insert */
227         new = kmem_cache_alloc(bh_kcache, 0);
228         assert(new);
229         new->bh_page = page;                                    /* weak ref */
230         new->bh_buffer = my_buf;
231         new->bh_flags = 0;
232         new->bh_next = bh;
233         new->bh_bdev = bdev;                                    /* uncounted ref */
234         new->bh_sector = blk_num * sct_per_blk;
235         new->bh_nr_sector = sct_per_blk;
236         /* Try to insert the new one in place.  If it fails, retry the whole "find
237          * the bh" process.  This should be rare, so no sense optimizing it. */
238         next_loc = prev ? &prev->bh_next : (struct buffer_head**)&page->pg_private;
239         /* Normally, there'd be an ABA problem here, but we never actually remove
240          * bhs from the chain until the whole page gets cleaned up, which can't
241          * happen while we hold a reference to the page. */
242         if (!atomic_cas_ptr((void**)next_loc, bh, new)) {
243                 kmem_cache_free(bh_kcache, new);
244                 goto retry;
245         }
246         bh = new;
247 found:
248         /* At this point, we have the BH for our buf, but it might not be up to
249          * date, and there might be someone else trying to update it. */
250         /* is it already here and up to date?  if so, we're done */
251         if (bh->bh_flags & BH_UPTODATE)
252                 return bh;
253         /* if not, try to lock the page (could BLOCK).  Using this for syncing. */
254         lock_page(page);
255         /* double check, are we up to date?  if so, we're done */
256         if (bh->bh_flags & BH_UPTODATE) {
257                 unlock_page(page);
258                 return bh;
259         }
260         /* if we're here, the page is locked by us, we need to read the block */
261         breq = kmem_cache_alloc(breq_kcache, 0);
262         assert(breq);
263         breq->flags = BREQ_READ;
264         breq->callback = generic_breq_done;
265         breq->data = 0;
266         init_sem(&breq->sem, 0);
267         breq->bhs = breq->local_bhs;
268         breq->bhs[0] = bh;
269         breq->nr_bhs = 1;
270         error = bdev_submit_request(bdev, breq);
271         assert(!error);
272         sleep_on_breq(breq);
273         kmem_cache_free(breq_kcache, breq);
274         /* after the data is read, we mark it up to date and unlock the page. */
275         bh->bh_flags |= BH_UPTODATE;
276         unlock_page(page);
277         return bh;
278 }
279
280 /* Will dirty the block/BH/page for the given block/buffer.  Will have to be
281  * careful with the page reclaimer - if someone holds a reference, they can
282  * still dirty it. */
283 void bdev_dirty_buffer(struct buffer_head *bh)
284 {
285         struct page *page = bh->bh_page;
286         /* TODO: race on flag modification */
287         bh->bh_flags |= BH_DIRTY;
288         page->pg_flags |= PG_DIRTY;
289 }
290
291 /* Decrefs the buffer from bdev_get_buffer().  Call this when you no longer
292  * reference your block/buffer.  For now, we do refcnting on the page, since the
293  * reclaiming will be in page sized chunks from the page cache. */
294 void bdev_put_buffer(struct buffer_head *bh)
295 {
296         page_decref(bh->bh_page);
297 }
298
299 /* Block device page map ops: */
300 struct page_map_operations block_pm_op = {
301         block_readpage,
302 };
303
304 /* Block device file ops: for now, we don't let you do much of anything */
305 struct file_operations block_f_op = {
306         dev_c_llseek,
307         0,
308         0,
309         kfs_readdir,    /* this will fail gracefully */
310         dev_mmap,
311         kfs_open,
312         kfs_flush,
313         kfs_release,
314         0,      /* fsync - makes no sense */
315         kfs_poll,
316         0,      /* readv */
317         0,      /* writev */
318         kfs_sendpage,
319         kfs_check_flags,
320 };