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         NULL                    /* 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                                         left = 0;
 147                                         break;
 148                                 }
 149                         }
 150                         if (left < BLOCK_SIZE - offset)
 151                                 chars = left;
 152                         else
 153                                 chars = BLOCK_SIZE - offset;
 154                         filp->f_pos += chars;
 155                         left -= chars;
 156                         read += chars;
 157                         if (*bhe) {
 158                                 memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
 159                                 brelse(*bhe);
 160                                 buf += chars;
 161                         } else {
 162                                 while (chars-->0)
 163                                         put_fs_byte(0,buf++);
 164                         }
 165                         offset = 0;
 166                         if (++bhe == &buflist[NBUF])
 167                                 bhe = buflist;
 168                 } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock));
 169         } while (left > 0);
 170 
 171 /* Release the read-ahead blocks */
 172         while (bhe != bhb) {
 173                 brelse(*bhe);
 174                 if (++bhe == &buflist[NBUF])
 175                         bhe = buflist;
 176         };
 177         if (!read)
 178                 return -EIO;
 179         filp->f_reada = 1;
 180         if (!IS_RDONLY(inode)) {
 181                 inode->i_atime = CURRENT_TIME;
 182                 inode->i_dirt = 1;
 183         }
 184         return read;
 185 }
 186 
 187 static int minix_file_write(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 188 {
 189         off_t pos;
 190         int written,c;
 191         struct buffer_head * bh;
 192         char * p;
 193 
 194         if (!inode) {
 195                 printk("minix_file_write: inode = NULL\n");
 196                 return -EINVAL;
 197         }
 198         if (!S_ISREG(inode->i_mode)) {
 199                 printk("minix_file_write: mode = %07o\n",inode->i_mode);
 200                 return -EINVAL;
 201         }
 202 /*
 203  * ok, append may not work when many processes are writing at the same time
 204  * but so what. That way leads to madness anyway.
 205  */
 206         if (filp->f_flags & O_APPEND)
 207                 pos = inode->i_size;
 208         else
 209                 pos = filp->f_pos;
 210         written = 0;
 211         while (written<count) {
 212                 bh = minix_getblk(inode,pos/BLOCK_SIZE,1);
 213                 if (!bh) {
 214                         if (!written)
 215                                 written = -ENOSPC;
 216                         break;
 217                 }
 218                 c = BLOCK_SIZE - (pos % BLOCK_SIZE);
 219                 if (c > count-written)
 220                         c = count-written;
 221                 if (c != BLOCK_SIZE && !bh->b_uptodate) {
 222                         ll_rw_block(READ, 1, &bh);
 223                         wait_on_buffer(bh);
 224                         if (!bh->b_uptodate) {
 225                                 brelse(bh);
 226                                 if (!written)
 227                                         written = -EIO;
 228                                 break;
 229                         }
 230                 }
 231                 p = (pos % BLOCK_SIZE) + bh->b_data;
 232                 pos += c;
 233                 if (pos > inode->i_size) {
 234                         inode->i_size = pos;
 235                         inode->i_dirt = 1;
 236                 }
 237                 written += c;
 238                 memcpy_fromfs(p,buf,c);
 239                 buf += c;
 240                 bh->b_uptodate = 1;
 241                 bh->b_dirt = 1;
 242                 brelse(bh);
 243         }
 244         inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 245         filp->f_pos = pos;
 246         inode->i_dirt = 1;
 247         return written;
 248 }

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