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         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                 blocks += read_ahead[MAJOR(inode->i_dev)] / (BLOCK_SIZE >> 9);
 102                 if (block + blocks > size)
 103                         blocks = size - block;
 104         }
 105 
 106         /* We do this in a two stage process.  We first try and request
 107            as many blocks as we can, then we wait for the first one to
 108            complete, and then we try and wrap up as many as are actually
 109            done.  This routine is rather generic, in that it can be used
 110            in a filesystem by substituting the appropriate function in
 111            for getblk.
 112 
 113            This routine is optimized to make maximum use of the various
 114            buffers and caches. */
 115 
 116         do {
 117                 bhrequest = 0;
 118                 uptodate = 1;
 119                 while (blocks) {
 120                         --blocks;
 121                         *bhb = minix_getblk(inode, block++, 0);
 122                         if (*bhb && !(*bhb)->b_uptodate) {
 123                                 uptodate = 0;
 124                                 bhreq[bhrequest++] = *bhb;
 125                         }
 126 
 127                         if (++bhb == &buflist[NBUF])
 128                                 bhb = buflist;
 129 
 130                         /* If the block we have on hand is uptodate, go ahead
 131                            and complete processing. */
 132                         if (uptodate)
 133                                 break;
 134                         if (bhb == bhe)
 135                                 break;
 136                 }
 137 
 138                 /* Now request them all */
 139                 if (bhrequest)
 140                         ll_rw_block(READ, bhrequest, bhreq);
 141 
 142                 do { /* Finish off all I/O that has actually completed */
 143                         if (*bhe) {
 144                                 wait_on_buffer(*bhe);
 145                                 if (!(*bhe)->b_uptodate) {      /* read error? */
 146                                         brelse(*bhe);
 147                                         if (++bhe == &buflist[NBUF])
 148                                           bhe = buflist;
 149                                         left = 0;
 150                                         break;
 151                                 }
 152                         }
 153                         if (left < BLOCK_SIZE - offset)
 154                                 chars = left;
 155                         else
 156                                 chars = BLOCK_SIZE - offset;
 157                         filp->f_pos += chars;
 158                         left -= chars;
 159                         read += chars;
 160                         if (*bhe) {
 161                                 memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
 162                                 brelse(*bhe);
 163                                 buf += chars;
 164                         } else {
 165                                 while (chars-->0)
 166                                         put_fs_byte(0,buf++);
 167                         }
 168                         offset = 0;
 169                         if (++bhe == &buflist[NBUF])
 170                                 bhe = buflist;
 171                 } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock));
 172         } while (left > 0);
 173 
 174 /* Release the read-ahead blocks */
 175         while (bhe != bhb) {
 176                 brelse(*bhe);
 177                 if (++bhe == &buflist[NBUF])
 178                         bhe = buflist;
 179         };
 180         if (!read)
 181                 return -EIO;
 182         filp->f_reada = 1;
 183         if (!IS_RDONLY(inode)) {
 184                 inode->i_atime = CURRENT_TIME;
 185                 inode->i_dirt = 1;
 186         }
 187         return read;
 188 }
 189 
 190 static int minix_file_write(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 191 {
 192         off_t pos;
 193         int written,c;
 194         struct buffer_head * bh;
 195         char * p;
 196 
 197         if (!inode) {
 198                 printk("minix_file_write: inode = NULL\n");
 199                 return -EINVAL;
 200         }
 201         if (!S_ISREG(inode->i_mode)) {
 202                 printk("minix_file_write: mode = %07o\n",inode->i_mode);
 203                 return -EINVAL;
 204         }
 205 /*
 206  * ok, append may not work when many processes are writing at the same time
 207  * but so what. That way leads to madness anyway.
 208  */
 209         if (filp->f_flags & O_APPEND)
 210                 pos = inode->i_size;
 211         else
 212                 pos = filp->f_pos;
 213         written = 0;
 214         while (written<count) {
 215                 bh = minix_getblk(inode,pos/BLOCK_SIZE,1);
 216                 if (!bh) {
 217                         if (!written)
 218                                 written = -ENOSPC;
 219                         break;
 220                 }
 221                 c = BLOCK_SIZE - (pos % BLOCK_SIZE);
 222                 if (c > count-written)
 223                         c = count-written;
 224                 if (c != BLOCK_SIZE && !bh->b_uptodate) {
 225                         ll_rw_block(READ, 1, &bh);
 226                         wait_on_buffer(bh);
 227                         if (!bh->b_uptodate) {
 228                                 brelse(bh);
 229                                 if (!written)
 230                                         written = -EIO;
 231                                 break;
 232                         }
 233                 }
 234                 p = (pos % BLOCK_SIZE) + bh->b_data;
 235                 pos += c;
 236                 if (pos > inode->i_size) {
 237                         inode->i_size = pos;
 238                         inode->i_dirt = 1;
 239                 }
 240                 written += c;
 241                 memcpy_fromfs(p,buf,c);
 242                 buf += c;
 243                 bh->b_uptodate = 1;
 244                 bh->b_dirt = 1;
 245                 brelse(bh);
 246         }
 247         inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 248         filp->f_pos = pos;
 249         inode->i_dirt = 1;
 250         return written;
 251 }

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