root/kernel/blk_drv/ll_rw_blk.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. lock_buffer
  2. unlock_buffer
  3. add_request
  4. make_request
  5. ll_rw_page
  6. ll_rw_block
  7. blk_dev_init
  8. ll_rw_swap_file

   1 /*
   2  *  linux/kernel/blk_dev/ll_rw.c
   3  *
   4  * (C) 1991 Linus Torvalds
   5  */
   6 
   7 /*
   8  * This handles all read/write requests to block devices
   9  */
  10 #include <errno.h>
  11 #include <linux/sched.h>
  12 #include <linux/kernel.h>
  13 #include <asm/system.h>
  14 
  15 #include "blk.h"
  16 
  17 /*
  18  * The request-struct contains all necessary data
  19  * to load a nr of sectors into memory
  20  */
  21 struct request request[NR_REQUEST];
  22 
  23 /*
  24  * used to wait on when there are no free requests
  25  */
  26 struct task_struct * wait_for_request = NULL;
  27 
  28 /* blk_dev_struct is:
  29  *      do_request-address
  30  *      next-request
  31  */
  32 struct blk_dev_struct blk_dev[NR_BLK_DEV] = {
  33         { NULL, NULL },         /* no_dev */
  34         { NULL, NULL },         /* dev mem */
  35         { NULL, NULL },         /* dev fd */
  36         { NULL, NULL },         /* dev hd */
  37         { NULL, NULL },         /* dev ttyx */
  38         { NULL, NULL },         /* dev tty */
  39         { NULL, NULL }          /* dev lp */
  40 };
  41 
  42 /*
  43  * blk_size contains the size of all block-devices:
  44  *
  45  * blk_size[MAJOR][MINOR]
  46  *
  47  * if (!blk_size[MAJOR]) then no minor size checking is done.
  48  */
  49 int * blk_size[NR_BLK_DEV] = { NULL, NULL, };
  50 
  51 static inline void lock_buffer(struct buffer_head * bh)
     /* [previous][next][first][last][top][bottom][index][help] */
  52 {
  53         cli();
  54         while (bh->b_lock)
  55                 sleep_on(&bh->b_wait);
  56         bh->b_lock=1;
  57         sti();
  58 }
  59 
  60 static inline void unlock_buffer(struct buffer_head * bh)
     /* [previous][next][first][last][top][bottom][index][help] */
  61 {
  62         if (!bh->b_lock)
  63                 printk("ll_rw_block.c: buffer not locked\n\r");
  64         bh->b_lock = 0;
  65         wake_up(&bh->b_wait);
  66 }
  67 
  68 /*
  69  * add-request adds a request to the linked list.
  70  * It disables interrupts so that it can muck with the
  71  * request-lists in peace.
  72  *
  73  * Note that swapping requests always go before other requests,
  74  * and are done in the order they appear.
  75  */
  76 static void add_request(struct blk_dev_struct * dev, struct request * req)
     /* [previous][next][first][last][top][bottom][index][help] */
  77 {
  78         struct request * tmp;
  79 
  80         req->next = NULL;
  81         cli();
  82         if (req->bh)
  83                 req->bh->b_dirt = 0;
  84         if (!(tmp = dev->current_request)) {
  85                 dev->current_request = req;
  86                 (dev->request_fn)();
  87                 sti();
  88                 return;
  89         }
  90         for ( ; tmp->next ; tmp = tmp->next) {
  91                 if (!req->bh)
  92                         if (tmp->next->bh)
  93                                 break;
  94                         else
  95                                 continue;
  96                 if ((IN_ORDER(tmp,req) ||
  97                     !IN_ORDER(tmp,tmp->next)) &&
  98                     IN_ORDER(req,tmp->next))
  99                         break;
 100         }
 101         req->next = tmp->next;
 102         tmp->next = req;
 103         sti();
 104 }
 105 
 106 static void make_request(int major,int rw, struct buffer_head * bh)
     /* [previous][next][first][last][top][bottom][index][help] */
 107 {
 108         struct request * req;
 109         int rw_ahead;
 110 
 111 /* WRITEA/READA is special case - it is not really needed, so if the */
 112 /* buffer is locked, we just forget about it, else it's a normal read */
 113         if (rw_ahead = (rw == READA || rw == WRITEA)) {
 114                 if (bh->b_lock)
 115                         return;
 116                 if (rw == READA)
 117                         rw = READ;
 118                 else
 119                         rw = WRITE;
 120         }
 121         if (rw!=READ && rw!=WRITE) {
 122                 printk("Bad block dev command, must be R/W/RA/WA\n");
 123                 return;
 124         }
 125         lock_buffer(bh);
 126         if ((rw == WRITE && !bh->b_dirt) || (rw == READ && bh->b_uptodate)) {
 127                 unlock_buffer(bh);
 128                 return;
 129         }
 130 repeat:
 131 /* we don't allow the write-requests to fill up the queue completely:
 132  * we want some room for reads: they take precedence. The last third
 133  * of the requests are only for reads.
 134  */
 135         if (rw == READ)
 136                 req = request+NR_REQUEST;
 137         else
 138                 req = request+((NR_REQUEST*2)/3);
 139 /* find an empty request */
 140         cli();
 141         while (--req >= request)
 142                 if (req->dev < 0)
 143                         goto found;
 144 /* if none found, sleep on new requests: check for rw_ahead */
 145         if (rw_ahead) {
 146                 sti();
 147                 unlock_buffer(bh);
 148                 return;
 149         }
 150         sleep_on(&wait_for_request);
 151         sti();
 152         goto repeat;
 153 
 154 found:  sti();
 155 /* fill up the request-info, and add it to the queue */
 156         req->dev = bh->b_dev;
 157         req->cmd = rw;
 158         req->errors=0;
 159         req->sector = bh->b_blocknr<<1;
 160         req->nr_sectors = 2;
 161         req->buffer = bh->b_data;
 162         req->waiting = NULL;
 163         req->bh = bh;
 164         req->next = NULL;
 165         add_request(major+blk_dev,req);
 166 }
 167 
 168 void ll_rw_page(int rw, int dev, int page, char * buffer)
     /* [previous][next][first][last][top][bottom][index][help] */
 169 {
 170         struct request * req;
 171         unsigned int major = MAJOR(dev);
 172 
 173         if (major >= NR_BLK_DEV || !(blk_dev[major].request_fn)) {
 174                 printk("Trying to read nonexistent block-device\n\r");
 175                 return;
 176         }
 177         if (rw!=READ && rw!=WRITE)
 178                 panic("Bad block dev command, must be R/W");
 179         cli();
 180 repeat:
 181         req = request+NR_REQUEST;
 182         while (--req >= request)
 183                 if (req->dev<0)
 184                         break;
 185         if (req < request) {
 186                 sleep_on(&wait_for_request);
 187                 goto repeat;
 188         }
 189         sti();
 190 /* fill up the request-info, and add it to the queue */
 191         req->dev = dev;
 192         req->cmd = rw;
 193         req->errors = 0;
 194         req->sector = page<<3;
 195         req->nr_sectors = 8;
 196         req->buffer = buffer;
 197         req->waiting = current;
 198         req->bh = NULL;
 199         req->next = NULL;
 200         current->state = TASK_UNINTERRUPTIBLE;
 201         add_request(major+blk_dev,req);
 202         schedule();
 203 }
 204 
 205 void ll_rw_block(int rw, struct buffer_head * bh)
     /* [previous][next][first][last][top][bottom][index][help] */
 206 {
 207         unsigned int major;
 208 
 209         if ((major=MAJOR(bh->b_dev)) >= NR_BLK_DEV ||
 210         !(blk_dev[major].request_fn)) {
 211                 printk("ll_rw_block: Trying to read nonexistent block-device\n\r");
 212                 return;
 213         }
 214         make_request(major,rw,bh);
 215 }
 216 
 217 void blk_dev_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 218 {
 219         int i;
 220 
 221         for (i=0 ; i<NR_REQUEST ; i++) {
 222                 request[i].dev = -1;
 223                 request[i].next = NULL;
 224         }
 225 }
 226 
 227 void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buf)
     /* [previous][next][first][last][top][bottom][index][help] */
 228 {
 229         int i;
 230         struct request * req;
 231         unsigned int major = MAJOR(dev);
 232 
 233         if (major >= NR_BLK_DEV || !(blk_dev[major].request_fn)) {
 234                 printk("ll_rw_swap_file: trying to swap nonexistent block-device\n\r");
 235                 return;
 236         }
 237 
 238         if (rw!=READ && rw!=WRITE) {
 239                 printk("ll_rw_swap: bad block dev command, must be R/W");
 240                 return;
 241         }
 242         
 243         for (i=0; i<nb; i++, buf += BLOCK_SIZE)
 244         {
 245 repeat:
 246                 req = request+NR_REQUEST;
 247                 while (--req >= request)
 248                         if (req->dev<0)
 249                                 break;
 250                 if (req < request) {
 251                         sleep_on(&wait_for_request);
 252                         goto repeat;
 253                 }
 254 
 255                 req->dev = dev;
 256                 req->cmd = rw;
 257                 req->errors = 0;
 258                 req->sector = b[i] << 1;
 259                 req->nr_sectors = 2;
 260                 req->buffer = buf;
 261                 req->waiting = current;
 262                 req->bh = NULL;
 263                 req->next = NULL;
 264                 current->state = TASK_UNINTERRUPTIBLE;
 265                 add_request(major+blk_dev,req);
 266                 schedule();
 267         }
 268 }

/* [previous][next][first][last][top][bottom][index][help] */