root/fs/block_dev.c

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

DEFINITIONS

This source file includes following definitions.
  1. block_write
  2. block_read
  3. block_fsync

   1 /*
   2  *  linux/fs/block_dev.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  */
   6 
   7 #include <linux/errno.h>
   8 #include <linux/sched.h>
   9 #include <linux/kernel.h>
  10 #include <linux/locks.h>
  11 #include <linux/fcntl.h>
  12 #include <linux/mm.h>
  13 
  14 #include <asm/segment.h>
  15 #include <asm/system.h>
  16 
  17 extern int *blk_size[];
  18 extern int *blksize_size[];
  19 
  20 #define MAX_BUF_PER_PAGE (PAGE_SIZE / 512)
  21 #define NBUF 64
  22 
  23 int block_write(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
  24 {
  25         int blocksize, blocksize_bits, i, j, buffercount,write_error;
  26         int block, blocks;
  27         loff_t offset;
  28         int chars;
  29         int written = 0;
  30         int cluster_list[MAX_BUF_PER_PAGE];
  31         struct buffer_head * bhlist[NBUF];
  32         int blocks_per_cluster;
  33         unsigned int size;
  34         unsigned int dev;
  35         struct buffer_head * bh, *bufferlist[NBUF];
  36         register char * p;
  37         int excess;
  38 
  39         write_error = buffercount = 0;
  40         dev = inode->i_rdev;
  41         if ( is_read_only( inode->i_rdev ))
  42                 return -EPERM;
  43         blocksize = BLOCK_SIZE;
  44         if (blksize_size[MAJOR(dev)] && blksize_size[MAJOR(dev)][MINOR(dev)])
  45                 blocksize = blksize_size[MAJOR(dev)][MINOR(dev)];
  46 
  47         i = blocksize;
  48         blocksize_bits = 0;
  49         while(i != 1) {
  50                 blocksize_bits++;
  51                 i >>= 1;
  52         }
  53 
  54         blocks_per_cluster = PAGE_SIZE / blocksize;
  55 
  56         block = filp->f_pos >> blocksize_bits;
  57         offset = filp->f_pos & (blocksize-1);
  58 
  59         if (blk_size[MAJOR(dev)])
  60                 size = ((loff_t) blk_size[MAJOR(dev)][MINOR(dev)] << BLOCK_SIZE_BITS) >> blocksize_bits;
  61         else
  62                 size = INT_MAX;
  63         while (count>0) {
  64                 if (block >= size)
  65                         return written;
  66                 chars = blocksize - offset;
  67                 if (chars > count)
  68                         chars=count;
  69 
  70 #if 0
  71                 if (chars == blocksize)
  72                         bh = getblk(dev, block, blocksize);
  73                 else
  74                         bh = breada(dev,block,block+1,block+2,-1);
  75 
  76 #else
  77                 for(i=0; i<blocks_per_cluster; i++) cluster_list[i] = block+i;
  78                 if((block % blocks_per_cluster) == 0)
  79                   generate_cluster(dev, cluster_list, blocksize);
  80                 bh = getblk(dev, block, blocksize);
  81 
  82                 if (chars != blocksize && !bh->b_uptodate) {
  83                   if(!filp->f_reada ||
  84                      !read_ahead[MAJOR(dev)]) {
  85                     /* We do this to force the read of a single buffer */
  86                     brelse(bh);
  87                     bh = bread(dev,block,blocksize);
  88                   } else {
  89                     /* Read-ahead before write */
  90                     blocks = read_ahead[MAJOR(dev)] / (blocksize >> 9) / 2;
  91                     if (block + blocks > size) blocks = size - block;
  92                     if (blocks > NBUF) blocks=NBUF;
  93                     excess = (block + blocks) % blocks_per_cluster;
  94                     if ( blocks > excess )
  95                         blocks -= excess;
  96                     bhlist[0] = bh;
  97                     for(i=1; i<blocks; i++){
  98                       if(((i+block) % blocks_per_cluster) == 0) {
  99                         for(j=0; j<blocks_per_cluster; j++) cluster_list[j] = block+i+j;
 100                         generate_cluster(dev, cluster_list, blocksize);
 101                       };
 102                       bhlist[i] = getblk (dev, block+i, blocksize);
 103                       if(!bhlist[i]){
 104                         while(i >= 0) brelse(bhlist[i--]);
 105                         return written? written: -EIO;
 106                       };
 107                     };
 108                     ll_rw_block(READ, blocks, bhlist);
 109                     for(i=1; i<blocks; i++) brelse(bhlist[i]);
 110                     wait_on_buffer(bh);
 111                       
 112                   };
 113                 };
 114 #endif
 115                 block++;
 116                 if (!bh)
 117                         return written?written:-EIO;
 118                 p = offset + bh->b_data;
 119                 offset = 0;
 120                 filp->f_pos += chars;
 121                 written += chars;
 122                 count -= chars;
 123                 memcpy_fromfs(p,buf,chars);
 124                 p += chars;
 125                 buf += chars;
 126                 bh->b_uptodate = 1;
 127                 mark_buffer_dirty(bh, 0);
 128                 if (filp->f_flags & O_SYNC)
 129                         bufferlist[buffercount++] = bh;
 130                 else
 131                         brelse(bh);
 132                 if (buffercount == NBUF){
 133                         ll_rw_block(WRITE, buffercount, bufferlist);
 134                         for(i=0; i<buffercount; i++){
 135                                 wait_on_buffer(bufferlist[i]);
 136                                 if (!bufferlist[i]->b_uptodate)
 137                                         write_error=1;
 138                                 brelse(bufferlist[i]);
 139                         }
 140                         buffercount=0;
 141                 }
 142                 if(write_error)
 143                         break;
 144         }
 145         if ( buffercount ){
 146                 ll_rw_block(WRITE, buffercount, bufferlist);
 147                 for(i=0; i<buffercount; i++){
 148                         wait_on_buffer(bufferlist[i]);
 149                         if (!bufferlist[i]->b_uptodate)
 150                                 write_error=1;
 151                         brelse(bufferlist[i]);
 152                 }
 153         }               
 154         filp->f_reada = 1;
 155         if(write_error)
 156                 return -EIO;
 157         return written;
 158 }
 159 
 160 int block_read(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 161 {
 162         unsigned int block;
 163         loff_t offset;
 164         int blocksize;
 165         int blocksize_bits, i;
 166         unsigned int blocks, rblocks, left;
 167         int bhrequest, uptodate;
 168         int cluster_list[MAX_BUF_PER_PAGE];
 169         int blocks_per_cluster;
 170         struct buffer_head ** bhb, ** bhe;
 171         struct buffer_head * buflist[NBUF];
 172         struct buffer_head * bhreq[NBUF];
 173         unsigned int chars;
 174         loff_t size;
 175         unsigned int dev;
 176         int read;
 177         int excess;
 178 
 179         dev = inode->i_rdev;
 180         blocksize = BLOCK_SIZE;
 181         if (blksize_size[MAJOR(dev)] && blksize_size[MAJOR(dev)][MINOR(dev)])
 182                 blocksize = blksize_size[MAJOR(dev)][MINOR(dev)];
 183         i = blocksize;
 184         blocksize_bits = 0;
 185         while (i != 1) {
 186                 blocksize_bits++;
 187                 i >>= 1;
 188         }
 189 
 190         offset = filp->f_pos;
 191         if (blk_size[MAJOR(dev)])
 192                 size = (loff_t) blk_size[MAJOR(dev)][MINOR(dev)] << BLOCK_SIZE_BITS;
 193         else
 194                 size = INT_MAX;
 195 
 196         blocks_per_cluster = PAGE_SIZE / blocksize;
 197 
 198         if (offset > size)
 199                 left = 0;
 200         else
 201                 left = size - offset;
 202         if (left > count)
 203                 left = count;
 204         if (left <= 0)
 205                 return 0;
 206         read = 0;
 207         block = offset >> blocksize_bits;
 208         offset &= blocksize-1;
 209         size >>= blocksize_bits;
 210         rblocks = blocks = (left + offset + blocksize - 1) >> blocksize_bits;
 211         bhb = bhe = buflist;
 212         if (filp->f_reada) {
 213                 if (blocks < read_ahead[MAJOR(dev)] / (blocksize >> 9))
 214                         blocks = read_ahead[MAJOR(dev)] / (blocksize >> 9);
 215                 excess = (block + blocks) % blocks_per_cluster;
 216                 if ( blocks > excess )
 217                         blocks -= excess;               
 218                 if (rblocks > blocks)
 219                         blocks = rblocks;
 220                 
 221         }
 222         if (block + blocks > size)
 223                 blocks = size - block;
 224 
 225         /* We do this in a two stage process.  We first try and request
 226            as many blocks as we can, then we wait for the first one to
 227            complete, and then we try and wrap up as many as are actually
 228            done.  This routine is rather generic, in that it can be used
 229            in a filesystem by substituting the appropriate function in
 230            for getblk.
 231 
 232            This routine is optimized to make maximum use of the various
 233            buffers and caches. */
 234 
 235         do {
 236                 bhrequest = 0;
 237                 uptodate = 1;
 238                 while (blocks) {
 239                         --blocks;
 240 #if 1
 241                         if((block % blocks_per_cluster) == 0) {
 242                           for(i=0; i<blocks_per_cluster; i++) cluster_list[i] = block+i;
 243                           generate_cluster(dev, cluster_list, blocksize);
 244                         }
 245 #endif
 246                         *bhb = getblk(dev, block++, blocksize);
 247                         if (*bhb && !(*bhb)->b_uptodate) {
 248                                 uptodate = 0;
 249                                 bhreq[bhrequest++] = *bhb;
 250                         }
 251 
 252                         if (++bhb == &buflist[NBUF])
 253                                 bhb = buflist;
 254 
 255                         /* If the block we have on hand is uptodate, go ahead
 256                            and complete processing. */
 257                         if (uptodate)
 258                                 break;
 259                         if (bhb == bhe)
 260                                 break;
 261                 }
 262 
 263                 /* Now request them all */
 264                 if (bhrequest) {
 265                         ll_rw_block(READ, bhrequest, bhreq);
 266                         refill_freelist(blocksize);
 267                 }
 268 
 269                 do { /* Finish off all I/O that has actually completed */
 270                         if (*bhe) {
 271                                 wait_on_buffer(*bhe);
 272                                 if (!(*bhe)->b_uptodate) {      /* read error? */
 273                                         brelse(*bhe);
 274                                         if (++bhe == &buflist[NBUF])
 275                                           bhe = buflist;
 276                                         left = 0;
 277                                         break;
 278                                 }
 279                         }                       
 280                         if (left < blocksize - offset)
 281                                 chars = left;
 282                         else
 283                                 chars = blocksize - offset;
 284                         filp->f_pos += chars;
 285                         left -= chars;
 286                         read += chars;
 287                         if (*bhe) {
 288                                 memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
 289                                 brelse(*bhe);
 290                                 buf += chars;
 291                         } else {
 292                                 while (chars-- > 0)
 293                                         put_user(0,buf++);
 294                         }
 295                         offset = 0;
 296                         if (++bhe == &buflist[NBUF])
 297                                 bhe = buflist;
 298                 } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock));
 299         } while (left > 0);
 300 
 301 /* Release the read-ahead blocks */
 302         while (bhe != bhb) {
 303                 brelse(*bhe);
 304                 if (++bhe == &buflist[NBUF])
 305                         bhe = buflist;
 306         };
 307         if (!read)
 308                 return -EIO;
 309         filp->f_reada = 1;
 310         return read;
 311 }
 312 
 313 int block_fsync(struct inode *inode, struct file *filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 314 {
 315         return fsync_dev (inode->i_rdev);
 316 }

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