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