root/fs/minix/file.c

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

DEFINITIONS

This source file includes following definitions.
  1. minix_file_read
  2. minix_file_write

   1 /*
   2  *  linux/fs/minix/file.c
   3  *
   4  *  Copyright (C) 1991, 1992 Linus Torvalds
   5  *
   6  *  minix regular file handling primitives
   7  */
   8 
   9 #include <asm/segment.h>
  10 #include <asm/system.h>
  11 
  12 #include <linux/sched.h>
  13 #include <linux/minix_fs.h>
  14 #include <linux/kernel.h>
  15 #include <linux/errno.h>
  16 #include <linux/fcntl.h>
  17 #include <linux/stat.h>
  18 #include <linux/locks.h>
  19 
  20 #define NBUF    16
  21 
  22 #define MIN(a,b) (((a)<(b))?(a):(b))
  23 #define MAX(a,b) (((a)>(b))?(a):(b))
  24 
  25 #include <linux/fs.h>
  26 #include <linux/minix_fs.h>
  27 
  28 static int minix_file_read(struct inode *, struct file *, char *, int);
  29 static int minix_file_write(struct inode *, struct file *, char *, int);
  30 
  31 /*
  32  * We have mostly NULL's here: the current defaults are ok for
  33  * the minix filesystem.
  34  */
  35 static struct file_operations minix_file_operations = {
  36         NULL,                   /* lseek - default */
  37         minix_file_read,        /* read */
  38         minix_file_write,       /* write */
  39         NULL,                   /* readdir - bad */
  40         NULL,                   /* select - default */
  41         NULL,                   /* ioctl - default */
  42         NULL,                   /* mmap */
  43         NULL,                   /* no special open is needed */
  44         NULL                    /* release */
  45 };
  46 
  47 struct inode_operations minix_file_inode_operations = {
  48         &minix_file_operations, /* default file operations */
  49         NULL,                   /* create */
  50         NULL,                   /* lookup */
  51         NULL,                   /* link */
  52         NULL,                   /* unlink */
  53         NULL,                   /* symlink */
  54         NULL,                   /* mkdir */
  55         NULL,                   /* rmdir */
  56         NULL,                   /* mknod */
  57         NULL,                   /* rename */
  58         NULL,                   /* readlink */
  59         NULL,                   /* follow_link */
  60         minix_bmap,             /* bmap */
  61         minix_truncate          /* truncate */
  62 };
  63 
  64 static int minix_file_read(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
  65 {
  66         int read,left,chars;
  67         int block, blocks, offset;
  68         int bhrequest, uptodate;
  69         struct buffer_head ** bhb, ** bhe;
  70         struct buffer_head * bhreq[NBUF];
  71         struct buffer_head * buflist[NBUF];
  72         unsigned int size;
  73 
  74         if (!inode) {
  75                 printk("minix_file_read: inode = NULL\n");
  76                 return -EINVAL;
  77         }
  78         if (!S_ISREG(inode->i_mode)) {
  79                 printk("minix_file_read: mode = %07o\n",inode->i_mode);
  80                 return -EINVAL;
  81         }
  82         offset = filp->f_pos;
  83         size = inode->i_size;
  84         if (offset > size)
  85                 left = 0;
  86         else
  87                 left = size - offset;
  88         if (left > count)
  89                 left = count;
  90         if (left <= 0)
  91                 return 0;
  92         read = 0;
  93         block = offset >> BLOCK_SIZE_BITS;
  94         offset &= BLOCK_SIZE-1;
  95         size = (size + (BLOCK_SIZE-1)) >> BLOCK_SIZE_BITS;
  96         blocks = (left + offset + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS;
  97         bhb = bhe = buflist;
  98         if (filp->f_reada) {
  99                 blocks += read_ahead[MAJOR(inode->i_dev)] / (BLOCK_SIZE >> 9);
 100                 if (block + blocks > size)
 101                         blocks = size - block;
 102         }
 103 
 104         /* We do this in a two stage process.  We first try and request
 105            as many blocks as we can, then we wait for the first one to
 106            complete, and then we try and wrap up as many as are actually
 107            done.  This routine is rather generic, in that it can be used
 108            in a filesystem by substituting the appropriate function in
 109            for getblk.
 110 
 111            This routine is optimized to make maximum use of the various
 112            buffers and caches. */
 113 
 114         do {
 115                 bhrequest = 0;
 116                 uptodate = 1;
 117                 while (blocks) {
 118                         --blocks;
 119                         *bhb = minix_getblk(inode, block++, 0);
 120                         if (*bhb && !(*bhb)->b_uptodate) {
 121                                 uptodate = 0;
 122                                 bhreq[bhrequest++] = *bhb;
 123                         }
 124 
 125                         if (++bhb == &buflist[NBUF])
 126                                 bhb = buflist;
 127 
 128                         /* If the block we have on hand is uptodate, go ahead
 129                            and complete processing. */
 130                         if (uptodate)
 131                                 break;
 132                         if (bhb == bhe)
 133                                 break;
 134                 }
 135 
 136                 /* Now request them all */
 137                 if (bhrequest)
 138                         ll_rw_block(READ, bhrequest, bhreq);
 139 
 140                 do { /* Finish off all I/O that has actually completed */
 141                         if (*bhe) {
 142                                 wait_on_buffer(*bhe);
 143                                 if (!(*bhe)->b_uptodate) {      /* read error? */
 144                                         left = 0;
 145                                         break;
 146                                 }
 147                         }
 148                         if (left < BLOCK_SIZE - offset)
 149                                 chars = left;
 150                         else
 151                                 chars = BLOCK_SIZE - offset;
 152                         filp->f_pos += chars;
 153                         left -= chars;
 154                         read += chars;
 155                         if (*bhe) {
 156                                 memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
 157                                 brelse(*bhe);
 158                                 buf += chars;
 159                         } else {
 160                                 while (chars-->0)
 161                                         put_fs_byte(0,buf++);
 162                         }
 163                         offset = 0;
 164                         if (++bhe == &buflist[NBUF])
 165                                 bhe = buflist;
 166                 } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock));
 167         } while (left > 0);
 168 
 169 /* Release the read-ahead blocks */
 170         while (bhe != bhb) {
 171                 brelse(*bhe);
 172                 if (++bhe == &buflist[NBUF])
 173                         bhe = buflist;
 174         };
 175         if (!read)
 176                 return -EIO;
 177         filp->f_reada = 1;
 178         if (!IS_RDONLY(inode)) {
 179                 inode->i_atime = CURRENT_TIME;
 180                 inode->i_dirt = 1;
 181         }
 182         return read;
 183 }
 184 
 185 static int minix_file_write(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 186 {
 187         off_t pos;
 188         int written,c;
 189         struct buffer_head * bh;
 190         char * p;
 191 
 192         if (!inode) {
 193                 printk("minix_file_write: inode = NULL\n");
 194                 return -EINVAL;
 195         }
 196         if (!S_ISREG(inode->i_mode)) {
 197                 printk("minix_file_write: mode = %07o\n",inode->i_mode);
 198                 return -EINVAL;
 199         }
 200 /*
 201  * ok, append may not work when many processes are writing at the same time
 202  * but so what. That way leads to madness anyway.
 203  */
 204         if (filp->f_flags & O_APPEND)
 205                 pos = inode->i_size;
 206         else
 207                 pos = filp->f_pos;
 208         written = 0;
 209         while (written<count) {
 210                 bh = minix_getblk(inode,pos/BLOCK_SIZE,1);
 211                 if (!bh) {
 212                         if (!written)
 213                                 written = -ENOSPC;
 214                         break;
 215                 }
 216                 c = BLOCK_SIZE - (pos % BLOCK_SIZE);
 217                 if (c > count-written)
 218                         c = count-written;
 219                 if (c != BLOCK_SIZE && !bh->b_uptodate) {
 220                         ll_rw_block(READ, 1, &bh);
 221                         wait_on_buffer(bh);
 222                         if (!bh->b_uptodate) {
 223                                 brelse(bh);
 224                                 if (!written)
 225                                         written = -EIO;
 226                                 break;
 227                         }
 228                 }
 229                 p = (pos % BLOCK_SIZE) + bh->b_data;
 230                 pos += c;
 231                 if (pos > inode->i_size) {
 232                         inode->i_size = pos;
 233                         inode->i_dirt = 1;
 234                 }
 235                 written += c;
 236                 memcpy_fromfs(p,buf,c);
 237                 buf += c;
 238                 bh->b_uptodate = 1;
 239                 bh->b_dirt = 1;
 240                 brelse(bh);
 241         }
 242         inode->i_mtime = CURRENT_TIME;
 243         inode->i_ctime = CURRENT_TIME;
 244         filp->f_pos = pos;
 245         inode->i_dirt = 1;
 246         return written;
 247 }

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