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 && !(*bhb)->b_uptodate) {
 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 (!(*bhe)->b_uptodate) {      /* 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 || !(*bhe)->b_lock));
 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         down(&inode->i_sem);
 205         if (filp->f_flags & O_APPEND)
 206                 pos = inode->i_size;
 207         else
 208                 pos = filp->f_pos;
 209         written = 0;
 210         while (written < count) {
 211                 bh = minix_getblk(inode,pos/BLOCK_SIZE,1);
 212                 if (!bh) {
 213                         if (!written)
 214                                 written = -ENOSPC;
 215                         break;
 216                 }
 217                 c = BLOCK_SIZE - (pos % BLOCK_SIZE);
 218                 if (c > count-written)
 219                         c = count-written;
 220                 if (c != BLOCK_SIZE && !bh->b_uptodate) {
 221                         ll_rw_block(READ, 1, &bh);
 222                         wait_on_buffer(bh);
 223                         if (!bh->b_uptodate) {
 224                                 brelse(bh);
 225                                 if (!written)
 226                                         written = -EIO;
 227                                 break;
 228                         }
 229                 }
 230                 p = (pos % BLOCK_SIZE) + bh->b_data;
 231                 pos += c;
 232                 written += c;
 233                 memcpy_fromfs(p,buf,c);
 234                 buf += c;
 235                 bh->b_uptodate = 1;
 236                 mark_buffer_dirty(bh, 0);
 237                 brelse(bh);
 238         }
 239         if (pos > inode->i_size)
 240                 inode->i_size = pos;
 241         up(&inode->i_sem);
 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] */