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         NULL,                   /* readpage */
  62         NULL,                   /* writepage */
  63         minix_bmap,             /* bmap */
  64         minix_truncate,         /* truncate */
  65         NULL                    /* permission */
  66 };
  67 
  68 static int minix_file_read(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
  69 {
  70         int read,left,chars;
  71         int block, blocks, offset;
  72         int bhrequest, uptodate;
  73         struct buffer_head ** bhb, ** bhe;
  74         struct buffer_head * bhreq[NBUF];
  75         struct buffer_head * buflist[NBUF];
  76         unsigned int size;
  77 
  78         if (!inode) {
  79                 printk("minix_file_read: inode = NULL\n");
  80                 return -EINVAL;
  81         }
  82         if (!S_ISREG(inode->i_mode)) {
  83                 printk("minix_file_read: mode = %07o\n",inode->i_mode);
  84                 return -EINVAL;
  85         }
  86         offset = filp->f_pos;
  87         size = inode->i_size;
  88         if (offset > size)
  89                 left = 0;
  90         else
  91                 left = size - offset;
  92         if (left > count)
  93                 left = count;
  94         if (left <= 0)
  95                 return 0;
  96         read = 0;
  97         block = offset >> BLOCK_SIZE_BITS;
  98         offset &= BLOCK_SIZE-1;
  99         size = (size + (BLOCK_SIZE-1)) >> BLOCK_SIZE_BITS;
 100         blocks = (left + offset + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS;
 101         bhb = bhe = buflist;
 102         if (filp->f_reada) {
 103                 if(blocks < read_ahead[MAJOR(inode->i_dev)] / (BLOCK_SIZE >> 9))
 104                   blocks = read_ahead[MAJOR(inode->i_dev)] / (BLOCK_SIZE >> 9);
 105                 if (block + blocks > size)
 106                         blocks = size - block;
 107         }
 108 
 109         /* We do this in a two stage process.  We first try and request
 110            as many blocks as we can, then we wait for the first one to
 111            complete, and then we try and wrap up as many as are actually
 112            done.  This routine is rather generic, in that it can be used
 113            in a filesystem by substituting the appropriate function in
 114            for getblk.
 115 
 116            This routine is optimized to make maximum use of the various
 117            buffers and caches. */
 118 
 119         do {
 120                 bhrequest = 0;
 121                 uptodate = 1;
 122                 while (blocks) {
 123                         --blocks;
 124                         *bhb = minix_getblk(inode, block++, 0);
 125                         if (*bhb && !buffer_uptodate(*bhb)) {
 126                                 uptodate = 0;
 127                                 bhreq[bhrequest++] = *bhb;
 128                         }
 129 
 130                         if (++bhb == &buflist[NBUF])
 131                                 bhb = buflist;
 132 
 133                         /* If the block we have on hand is uptodate, go ahead
 134                            and complete processing. */
 135                         if (uptodate)
 136                                 break;
 137                         if (bhb == bhe)
 138                                 break;
 139                 }
 140 
 141                 /* Now request them all */
 142                 if (bhrequest)
 143                         ll_rw_block(READ, bhrequest, bhreq);
 144 
 145                 do { /* Finish off all I/O that has actually completed */
 146                         if (*bhe) {
 147                                 wait_on_buffer(*bhe);
 148                                 if (!buffer_uptodate(*bhe)) {   /* read error? */
 149                                         brelse(*bhe);
 150                                         if (++bhe == &buflist[NBUF])
 151                                           bhe = buflist;
 152                                         left = 0;
 153                                         break;
 154                                 }
 155                         }
 156                         if (left < BLOCK_SIZE - offset)
 157                                 chars = left;
 158                         else
 159                                 chars = BLOCK_SIZE - offset;
 160                         filp->f_pos += chars;
 161                         left -= chars;
 162                         read += chars;
 163                         if (*bhe) {
 164                                 memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
 165                                 brelse(*bhe);
 166                                 buf += chars;
 167                         } else {
 168                                 while (chars-->0)
 169                                         put_user(0,buf++);
 170                         }
 171                         offset = 0;
 172                         if (++bhe == &buflist[NBUF])
 173                                 bhe = buflist;
 174                 } while (left > 0 && bhe != bhb && (!*bhe || !buffer_locked(*bhe)));
 175         } while (left > 0);
 176 
 177 /* Release the read-ahead blocks */
 178         while (bhe != bhb) {
 179                 brelse(*bhe);
 180                 if (++bhe == &buflist[NBUF])
 181                         bhe = buflist;
 182         };
 183         if (!read)
 184                 return -EIO;
 185         filp->f_reada = 1;
 186         if (!IS_RDONLY(inode))
 187                 inode->i_atime = CURRENT_TIME;
 188         return read;
 189 }
 190 
 191 static int minix_file_write(struct inode * inode, struct file * filp, const char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 192 {
 193         off_t pos;
 194         int written,c;
 195         struct buffer_head * bh;
 196         char * p;
 197 
 198         if (!inode) {
 199                 printk("minix_file_write: inode = NULL\n");
 200                 return -EINVAL;
 201         }
 202         if (!S_ISREG(inode->i_mode)) {
 203                 printk("minix_file_write: mode = %07o\n",inode->i_mode);
 204                 return -EINVAL;
 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 && !buffer_uptodate(bh)) {
 222                         ll_rw_block(READ, 1, &bh);
 223                         wait_on_buffer(bh);
 224                         if (!buffer_uptodate(bh)) {
 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                 written += c;
 234                 memcpy_fromfs(p,buf,c);
 235                 buf += c;
 236                 mark_buffer_uptodate(bh, 1);
 237                 mark_buffer_dirty(bh, 0);
 238                 brelse(bh);
 239         }
 240         if (pos > inode->i_size)
 241                 inode->i_size = pos;
 242         inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 243         filp->f_pos = pos;
 244         inode->i_dirt = 1;
 245         return written;
 246 }

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