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 <linux/sched.h>
  10 #include <linux/minix_fs.h>
  11 #include <linux/kernel.h>
  12 #include <linux/errno.h>
  13 #include <linux/fcntl.h>
  14 #include <linux/stat.h>
  15 #include <linux/locks.h>
  16 
  17 #include <asm/segment.h>
  18 #include <asm/system.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 *, const 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 && !buffer_uptodate(*bhb)) {
 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 (!buffer_uptodate(*bhe)) {   /* 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_user(0,buf++);
 168                         }
 169                         offset = 0;
 170                         if (++bhe == &buflist[NBUF])
 171                                 bhe = buflist;
 172                 } while (left > 0 && bhe != bhb && (!*bhe || !buffer_locked(*bhe)));
 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, const 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         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 && !buffer_uptodate(bh)) {
 220                         ll_rw_block(READ, 1, &bh);
 221                         wait_on_buffer(bh);
 222                         if (!buffer_uptodate(bh)) {
 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                 written += c;
 232                 memcpy_fromfs(p,buf,c);
 233                 buf += c;
 234                 mark_buffer_uptodate(bh, 1);
 235                 mark_buffer_dirty(bh, 0);
 236                 brelse(bh);
 237         }
 238         if (pos > inode->i_size)
 239                 inode->i_size = pos;
 240         inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 241         filp->f_pos = pos;
 242         inode->i_dirt = 1;
 243         return written;
 244 }

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