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 #ifdef MODULE
  10 #include <linux/module.h>
  11 #endif
  12 
  13 #include <asm/segment.h>
  14 #include <asm/system.h>
  15 
  16 #include <linux/sched.h>
  17 #include <linux/minix_fs.h>
  18 #include <linux/kernel.h>
  19 #include <linux/errno.h>
  20 #include <linux/fcntl.h>
  21 #include <linux/stat.h>
  22 #include <linux/locks.h>
  23 
  24 #define NBUF    32
  25 
  26 #define MIN(a,b) (((a)<(b))?(a):(b))
  27 #define MAX(a,b) (((a)>(b))?(a):(b))
  28 
  29 #include <linux/fs.h>
  30 #include <linux/minix_fs.h>
  31 
  32 static int minix_file_read(struct inode *, struct file *, char *, int);
  33 static int minix_file_write(struct inode *, struct file *, char *, int);
  34 
  35 /*
  36  * We have mostly NULL's here: the current defaults are ok for
  37  * the minix filesystem.
  38  */
  39 static struct file_operations minix_file_operations = {
  40         NULL,                   /* lseek - default */
  41         minix_file_read,        /* read */
  42         minix_file_write,       /* write */
  43         NULL,                   /* readdir - bad */
  44         NULL,                   /* select - default */
  45         NULL,                   /* ioctl - default */
  46         generic_mmap,           /* mmap */
  47         NULL,                   /* no special open is needed */
  48         NULL,                   /* release */
  49         minix_sync_file         /* fsync */
  50 };
  51 
  52 struct inode_operations minix_file_inode_operations = {
  53         &minix_file_operations, /* default file operations */
  54         NULL,                   /* create */
  55         NULL,                   /* lookup */
  56         NULL,                   /* link */
  57         NULL,                   /* unlink */
  58         NULL,                   /* symlink */
  59         NULL,                   /* mkdir */
  60         NULL,                   /* rmdir */
  61         NULL,                   /* mknod */
  62         NULL,                   /* rename */
  63         NULL,                   /* readlink */
  64         NULL,                   /* follow_link */
  65         minix_bmap,             /* bmap */
  66         minix_truncate,         /* truncate */
  67         NULL                    /* permission */
  68 };
  69 
  70 static int minix_file_read(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
  71 {
  72         int read,left,chars;
  73         int block, blocks, offset;
  74         int bhrequest, uptodate;
  75         struct buffer_head ** bhb, ** bhe;
  76         struct buffer_head * bhreq[NBUF];
  77         struct buffer_head * buflist[NBUF];
  78         unsigned int size;
  79 
  80         if (!inode) {
  81                 printk("minix_file_read: inode = NULL\n");
  82                 return -EINVAL;
  83         }
  84         if (!S_ISREG(inode->i_mode)) {
  85                 printk("minix_file_read: mode = %07o\n",inode->i_mode);
  86                 return -EINVAL;
  87         }
  88         offset = filp->f_pos;
  89         size = inode->i_size;
  90         if (offset > size)
  91                 left = 0;
  92         else
  93                 left = size - offset;
  94         if (left > count)
  95                 left = count;
  96         if (left <= 0)
  97                 return 0;
  98         read = 0;
  99         block = offset >> BLOCK_SIZE_BITS;
 100         offset &= BLOCK_SIZE-1;
 101         size = (size + (BLOCK_SIZE-1)) >> BLOCK_SIZE_BITS;
 102         blocks = (left + offset + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS;
 103         bhb = bhe = buflist;
 104         if (filp->f_reada) {
 105                 if(blocks < read_ahead[MAJOR(inode->i_dev)] / (BLOCK_SIZE >> 9))
 106                   blocks = read_ahead[MAJOR(inode->i_dev)] / (BLOCK_SIZE >> 9);
 107                 if (block + blocks > size)
 108                         blocks = size - block;
 109         }
 110 
 111         /* We do this in a two stage process.  We first try and request
 112            as many blocks as we can, then we wait for the first one to
 113            complete, and then we try and wrap up as many as are actually
 114            done.  This routine is rather generic, in that it can be used
 115            in a filesystem by substituting the appropriate function in
 116            for getblk.
 117 
 118            This routine is optimized to make maximum use of the various
 119            buffers and caches. */
 120 
 121         do {
 122                 bhrequest = 0;
 123                 uptodate = 1;
 124                 while (blocks) {
 125                         --blocks;
 126                         *bhb = minix_getblk(inode, block++, 0);
 127                         if (*bhb && !(*bhb)->b_uptodate) {
 128                                 uptodate = 0;
 129                                 bhreq[bhrequest++] = *bhb;
 130                         }
 131 
 132                         if (++bhb == &buflist[NBUF])
 133                                 bhb = buflist;
 134 
 135                         /* If the block we have on hand is uptodate, go ahead
 136                            and complete processing. */
 137                         if (uptodate)
 138                                 break;
 139                         if (bhb == bhe)
 140                                 break;
 141                 }
 142 
 143                 /* Now request them all */
 144                 if (bhrequest)
 145                         ll_rw_block(READ, bhrequest, bhreq);
 146 
 147                 do { /* Finish off all I/O that has actually completed */
 148                         if (*bhe) {
 149                                 wait_on_buffer(*bhe);
 150                                 if (!(*bhe)->b_uptodate) {      /* read error? */
 151                                         brelse(*bhe);
 152                                         if (++bhe == &buflist[NBUF])
 153                                           bhe = buflist;
 154                                         left = 0;
 155                                         break;
 156                                 }
 157                         }
 158                         if (left < BLOCK_SIZE - offset)
 159                                 chars = left;
 160                         else
 161                                 chars = BLOCK_SIZE - offset;
 162                         filp->f_pos += chars;
 163                         left -= chars;
 164                         read += chars;
 165                         if (*bhe) {
 166                                 memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
 167                                 brelse(*bhe);
 168                                 buf += chars;
 169                         } else {
 170                                 while (chars-->0)
 171                                         put_user(0,buf++);
 172                         }
 173                         offset = 0;
 174                         if (++bhe == &buflist[NBUF])
 175                                 bhe = buflist;
 176                 } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock));
 177         } while (left > 0);
 178 
 179 /* Release the read-ahead blocks */
 180         while (bhe != bhb) {
 181                 brelse(*bhe);
 182                 if (++bhe == &buflist[NBUF])
 183                         bhe = buflist;
 184         };
 185         if (!read)
 186                 return -EIO;
 187         filp->f_reada = 1;
 188         if (!IS_RDONLY(inode))
 189                 inode->i_atime = CURRENT_TIME;
 190         return read;
 191 }
 192 
 193 static int minix_file_write(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 194 {
 195         off_t pos;
 196         int written,c;
 197         struct buffer_head * bh;
 198         char * p;
 199 
 200         if (!inode) {
 201                 printk("minix_file_write: inode = NULL\n");
 202                 return -EINVAL;
 203         }
 204         if (!S_ISREG(inode->i_mode)) {
 205                 printk("minix_file_write: mode = %07o\n",inode->i_mode);
 206                 return -EINVAL;
 207         }
 208         down(&inode->i_sem);
 209         if (filp->f_flags & O_APPEND)
 210                 pos = inode->i_size;
 211         else
 212                 pos = filp->f_pos;
 213         written = 0;
 214         while (written < count) {
 215                 bh = minix_getblk(inode,pos/BLOCK_SIZE,1);
 216                 if (!bh) {
 217                         if (!written)
 218                                 written = -ENOSPC;
 219                         break;
 220                 }
 221                 c = BLOCK_SIZE - (pos % BLOCK_SIZE);
 222                 if (c > count-written)
 223                         c = count-written;
 224                 if (c != BLOCK_SIZE && !bh->b_uptodate) {
 225                         ll_rw_block(READ, 1, &bh);
 226                         wait_on_buffer(bh);
 227                         if (!bh->b_uptodate) {
 228                                 brelse(bh);
 229                                 if (!written)
 230                                         written = -EIO;
 231                                 break;
 232                         }
 233                 }
 234                 p = (pos % BLOCK_SIZE) + bh->b_data;
 235                 pos += c;
 236                 written += c;
 237                 memcpy_fromfs(p,buf,c);
 238                 buf += c;
 239                 bh->b_uptodate = 1;
 240                 mark_buffer_dirty(bh, 0);
 241                 brelse(bh);
 242         }
 243         if (pos > inode->i_size)
 244                 inode->i_size = pos;
 245         up(&inode->i_sem);
 246         inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 247         filp->f_pos = pos;
 248         inode->i_dirt = 1;
 249         return written;
 250 }

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