source: trunk/kernel/kern/blkio.c @ 176

Last change on this file since 176 was 5, checked in by alain, 8 years ago

Introduce the chdev_t structure in place of the device_t structure.

File size: 5.8 KB
Line 
1/*
2 * blkio.c - provides per-page buffers I/O
3 *
4 * Copyright (c) 2008,2009,2010,2011,2012 Ghassan Almaless
5 * Copyright (c) 2011,2012 UPMC Sorbonne Universites
6 *
7 * This file is part of ALMOS-kernel.
8 *
9 * ALMOS-kernel is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2.0 of the License.
12 *
13 * ALMOS-kernel is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with ALMOS-kernel; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#include <cpu.h>
24#include <errno.h>
25#include <scheduler.h>
26#include <kmem.h>
27#include <thread.h>
28#include <chdev.h>
29#include <driver.h>
30#include <event.h>
31#include <atomic.h>
32#include <cluster.h>
33#include <page.h>
34#include <blkio.h>
35
36static EVENT_HANDLER(blkio_async)
37{
38        struct blkio_s *blkio;
39        struct blkio_s *info;
40        struct page_s *page;
41        struct thread_s *thread;
42        error_t err;
43        uint_t irq_state;
44
45        blkio = event_get_argument(event);
46        page  = blkio->b_page;
47        info  = list_head(&page->root, struct blkio_s, b_list);
48        err   = event_get_error(event);
49
50        if(err)
51        {
52                printk(WARNING, "WARNING: %s: Requested I/O is failed, blk %d\n", 
53                       __FUNCTION__, 
54                       blkio->b_dev_rq.src);
55        }
56
57        err = (err) ? 1 : 0;
58
59        spinlock_lock_noirq(&info->b_ctrl.lock, &irq_state);
60
61        info->b_ctrl.cntr ++;
62        info->b_ctrl.error = (info->b_ctrl.error) ? 1 : err;
63
64        if(info->b_ctrl.cntr == info->b_ctrl.count) 
65        {
66                thread = wakeup_one(&info->b_ctrl.wait, WAIT_ANY);
67
68#if CONFIG_BLKIO_DEBUG   
69                if(thread != NULL)
70                {
71                        printk(INFO, "%s: cpu %d, wakeup tid %d on cpu %d [%u]\n",
72                               __FUNCTION__,
73                               cpu_get_id(),
74                               thread->info.order,
75                               thread_current_cpu(thread)->gid,
76                               cpu_time_stamp());
77                }
78#endif
79        }
80
81        spinlock_unlock_noirq(&info->b_ctrl.lock, irq_state);
82        return 0;
83}
84
85static void blkio_ctor(struct kcm_s *kcm, void *ptr) 
86{
87        struct blkio_s *blkio = (struct blkio_s *)ptr;
88
89        spinlock_init(&blkio->b_ctrl.lock, "BlkIO");
90        event_set_handler(&blkio->b_dev_rq.event, blkio_async);
91        event_set_priority(&blkio->b_dev_rq.event, E_BLK);
92        event_set_argument(&blkio->b_dev_rq.event, blkio);
93        wait_queue_init(&blkio->b_ctrl.wait, "BLKIO Sync");
94}
95
96KMEM_OBJATTR_INIT(blkio_kmem_init)
97{
98        attr->type = KMEM_BLKIO;
99        attr->name = "KCM BLKIO";
100        attr->size = sizeof(struct blkio_s);
101        attr->aligne = 0;
102        attr->min = CONFIG_BLKIO_MIN;
103        attr->max = CONFIG_BLKIO_MAX;
104        attr->ctor = blkio_ctor;
105        attr->dtor = NULL;
106        return 0;
107}
108
109///////////////////////////////////
110error_t blkio_init( device_t * dev,
111                    page_t   * page,
112                    uint32_t   count ) 
113{
114        kmem_req_t req;
115        struct blkio_s *blkio;
116        uint_t blkio_nr;
117
118        req.type  = KMEM_BLKIO;
119        req.size  = sizeof(*blkio);
120        req.flags = AF_KERNEL;
121 
122        slist_root_init(&page->root);
123        blkio_nr = count;
124
125#if CONFIG_BLKIO_DEBUG   
126        printk(INFO, "%s: cpu %d, count %d, pg @0x%x, index %d [%d]\n",
127               __FUNCTION__, 
128               cpu_get_id(),
129               count, 
130               page, 
131               page->index,
132               cpu_time_stamp());
133#endif
134
135        while(count)
136        {
137                if((blkio = kmem_alloc(&req)) == NULL) 
138                {
139                        blkio_destroy(page);
140                        return ENOMEM;
141                }
142   
143                blkio->b_flags = 0;
144                blkio->b_page  = page;
145                blkio->b_dev   = dev;
146
147                list_push(&page->root, &blkio->b_list);
148                count -= 1;
149        }
150
151        blkio = list_head(&page->root, struct blkio_s, b_list);
152
153        blkio->b_ctrl.count = blkio_nr;
154        blkio->b_ctrl.cntr  = 0;
155        blkio->b_ctrl.error = 0;
156
157        PAGE_SET(page, PG_BUFFER);
158        return 0;
159}  // end blkio_init()
160
161
162////////////////////////////////////
163error_t blkio_sync( page_t   * page,
164                    uint32_t   flags ) 
165{
166        slist_entry_t    * iter;
167        blkio_t          * blkio;
168        blkio_t          * info;
169        device_request_t * handler;
170        error_t            err;
171        uint32_t           irq_state;
172        uint32_t           cntr;
173
174        info = list_head(&page->root, struct blkio_s, b_list);
175        handler = (flags & BLKIO_RD) ? info->b_dev->op.dev.read : info->b_dev->op.dev.write;
176        cntr =  0;
177        err =  0;
178
179        list_foreach(&page->root, iter) 
180        {
181                blkio = list_element(iter, struct blkio_s, b_list);
182
183                if(blkio->b_flags & BLKIO_INIT)
184                {
185                        blkio->b_flags &= ~BLKIO_INIT;
186                        continue;
187                }
188
189                blkio->b_dev_rq.flags = DEV_RQ_NOBLOCK;
190
191#if CONFIG_BLKIO_DEBUG 
192                printk(INFO, "%s: cpu %d, Submitting blkio #%d, src %d, dst %x [%d]\n",
193                       __FUNCTION__, 
194                       cpu_get_id(),
195                       cntr, 
196                       blkio->b_dev_rq.src, 
197                       blkio->b_dev_rq.dst, 
198                       cpu_time_stamp());
199#endif
200
201                err = handler(blkio->b_dev, &blkio->b_dev_rq);
202   
203                if(err < 0) 
204                {
205                        err = EIO;
206                        break;
207                }
208
209                cntr ++;
210        }
211
212        if(flags & BLKIO_SYNC) 
213        {
214                spinlock_lock_noirq(&info->b_ctrl.lock, &irq_state);
215   
216                info->b_ctrl.cntr += (info->b_ctrl.count - cntr);
217
218                if(info->b_ctrl.cntr < info->b_ctrl.count) 
219                {
220                        wait_on(&info->b_ctrl.wait, WAIT_ANY);
221                        spinlock_unlock_noirq(&info->b_ctrl.lock, irq_state);
222                        sched_sleep(CURRENT_THREAD);
223
224#if CONFIG_BLKIO_DEBUG
225                        printk(INFO, "%s: cpu %d, tid %d, blkio ended, err %d\n",
226                               __FUNCTION__, 
227                               cpu_get_id(), 
228                               CURRENT_THREAD->info.order, 
229                               info->b_ctrl.error);
230#endif
231
232                }
233                else
234                        spinlock_unlock_noirq(&info->b_ctrl.lock, irq_state);
235
236                return (info->b_ctrl.error) ? EIO : 0;
237        }
238
239        return err;
240}
241
242//////////////////////////////////////////
243error_t blkio_destroy(struct page_s *page) 
244{
245        kmem_req_t req;
246        struct slist_entry *iter;
247
248        req.type = KMEM_BLKIO;
249
250        list_foreach(&page->root, iter) 
251        {
252                req.ptr = list_element(iter, struct blkio_s, b_list);
253                kmem_free(&req);
254        }
255
256        page->private = 0;
257        PAGE_CLEAR(page, PG_BUFFER);
258        return 0;
259}
Note: See TracBrowser for help on using the repository browser.