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

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