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                 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         return read;
 186 }
 187 
 188 static int minix_file_write(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 189 {
 190         off_t pos;
 191         int written,c;
 192         struct buffer_head * bh;
 193         char * p;
 194 
 195         if (!inode) {
 196                 printk("minix_file_write: inode = NULL\n");
 197                 return -EINVAL;
 198         }
 199         if (!S_ISREG(inode->i_mode)) {
 200                 printk("minix_file_write: mode = %07o\n",inode->i_mode);
 201                 return -EINVAL;
 202         }
 203 /*
 204  * ok, append may not work when many processes are writing at the same time
 205  * but so what. That way leads to madness anyway.
 206  */
 207         if (filp->f_flags & O_APPEND)
 208                 pos = inode->i_size;
 209         else
 210                 pos = filp->f_pos;
 211         written = 0;
 212         while (written<count) {
 213                 bh = minix_getblk(inode,pos/BLOCK_SIZE,1);
 214                 if (!bh) {
 215                         if (!written)
 216                                 written = -ENOSPC;
 217                         break;
 218                 }
 219                 c = BLOCK_SIZE - (pos % BLOCK_SIZE);
 220                 if (c > count-written)
 221                         c = count-written;
 222                 if (c != BLOCK_SIZE && !bh->b_uptodate) {
 223                         ll_rw_block(READ, 1, &bh);
 224                         wait_on_buffer(bh);
 225                         if (!bh->b_uptodate) {
 226                                 brelse(bh);
 227                                 if (!written)
 228                                         written = -EIO;
 229                                 break;
 230                         }
 231                 }
 232                 p = (pos % BLOCK_SIZE) + bh->b_data;
 233                 pos += c;
 234                 if (pos > inode->i_size) {
 235                         inode->i_size = pos;
 236                         inode->i_dirt = 1;
 237                 }
 238                 written += c;
 239                 memcpy_fromfs(p,buf,c);
 240                 buf += c;
 241                 bh->b_uptodate = 1;
 242                 bh->b_dirt = 1;
 243                 brelse(bh);
 244         }
 245         inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 246         filp->f_pos = pos;
 247         inode->i_dirt = 1;
 248         return written;
 249 }

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