root/fs/minix/file.c

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

DEFINITIONS

This source file includes following definitions.
  1. wait_on_buffer
  2. minix_file_read
  3. 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 
  19 #define NBUF    16
  20 
  21 #define MIN(a,b) (((a)<(b))?(a):(b))
  22 #define MAX(a,b) (((a)>(b))?(a):(b))
  23 
  24 #include <linux/fs.h>
  25 #include <linux/minix_fs.h>
  26 
  27 int minix_file_read(struct inode *, struct file *, char *, int);
  28 static int minix_file_write(struct inode *, struct file *, char *, int);
  29 
  30 /*
  31  * We have mostly NULL's here: the current defaults are ok for
  32  * the minix filesystem.
  33  */
  34 static struct file_operations minix_file_operations = {
  35         NULL,                   /* lseek - default */
  36         minix_file_read,        /* read */
  37         minix_file_write,       /* write */
  38         NULL,                   /* readdir - bad */
  39         NULL,                   /* select - default */
  40         NULL,                   /* ioctl - default */
  41         NULL,                   /* no special open is needed */
  42         NULL                    /* release */
  43 };
  44 
  45 struct inode_operations minix_file_inode_operations = {
  46         &minix_file_operations, /* default file operations */
  47         NULL,                   /* create */
  48         NULL,                   /* lookup */
  49         NULL,                   /* link */
  50         NULL,                   /* unlink */
  51         NULL,                   /* symlink */
  52         NULL,                   /* mkdir */
  53         NULL,                   /* rmdir */
  54         NULL,                   /* mknod */
  55         NULL,                   /* rename */
  56         NULL,                   /* readlink */
  57         NULL,                   /* follow_link */
  58         minix_bmap,             /* bmap */
  59         minix_truncate          /* truncate */
  60 };
  61 
  62 static inline void wait_on_buffer(struct buffer_head * bh)
     /* [previous][next][first][last][top][bottom][index][help] */
  63 {
  64         cli();
  65         while (bh->b_lock)
  66                 sleep_on(&bh->b_wait);
  67         sti();
  68 }
  69 
  70 /*
  71  * minix_file_read() is also needed by the directory read-routine,
  72  * so it's not static. NOTE! reading directories directly is a bad idea,
  73  * but has to be supported for now for compatability reasons with older
  74  * versions.
  75  */
  76 int minix_file_read(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
  77 {
  78         int read,left,chars,nr;
  79         int block, blocks, offset;
  80         struct buffer_head ** bhb, ** bhe;
  81         struct buffer_head * buflist[NBUF];
  82 
  83         if (!inode) {
  84                 printk("minix_file_read: inode = NULL\n");
  85                 return -EINVAL;
  86         }
  87         if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) {
  88                 printk("minix_file_read: mode = %07o\n",inode->i_mode);
  89                 return -EINVAL;
  90         }
  91         if (filp->f_pos > inode->i_size)
  92                 left = 0;
  93         else
  94                 left = inode->i_size - filp->f_pos;
  95         if (left > count)
  96                 left = count;
  97         if (left <= 0)
  98                 return 0;
  99         read = 0;
 100         block = filp->f_pos >> BLOCK_SIZE_BITS;
 101         offset = filp->f_pos & (BLOCK_SIZE-1);
 102         blocks = (left + offset + BLOCK_SIZE - 1) / BLOCK_SIZE;
 103         bhb = bhe = buflist;
 104         do {
 105                 if (blocks) {
 106                         --blocks;
 107                         if (nr = minix_bmap(inode,block++)) {
 108                                 *bhb = getblk(inode->i_dev,nr,BLOCK_SIZE);
 109                                 if (!(*bhb)->b_uptodate)
 110                                         ll_rw_block(READ,*bhb);
 111                         } else
 112                                 *bhb = NULL;
 113 
 114                         if (++bhb == &buflist[NBUF])
 115                                 bhb = buflist;
 116 
 117                         if (bhb != bhe)
 118                                 continue;
 119                 }
 120                 if (*bhe) {
 121                         wait_on_buffer(*bhe);
 122                         if (!(*bhe)->b_uptodate) {
 123                                 do {
 124                                         brelse(*bhe);
 125                                         if (++bhe == &buflist[NBUF])
 126                                                 bhe = buflist;
 127                                 } while (bhe != bhb);
 128                                 break;
 129                         }
 130                 }
 131 
 132                 if (left < BLOCK_SIZE - offset)
 133                         chars = left;
 134                 else
 135                         chars = BLOCK_SIZE - offset;
 136                 filp->f_pos += chars;
 137                 left -= chars;
 138                 read += chars;
 139                 if (*bhe) {
 140                         memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
 141                         brelse(*bhe);
 142                         buf += chars;
 143                 } else {
 144                         while (chars-->0)
 145                                 put_fs_byte(0,buf++);
 146                 }
 147                 offset = 0;
 148                 if (++bhe == &buflist[NBUF])
 149                         bhe = buflist;
 150         } while (left > 0);
 151         if (!read)
 152                 return -EIO;
 153         if (!IS_RDONLY(inode)) {
 154                 inode->i_atime = CURRENT_TIME;
 155                 inode->i_dirt = 1;
 156         }
 157         return read;
 158 }
 159 
 160 static int minix_file_write(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 161 {
 162         off_t pos;
 163         int written,block,c;
 164         struct buffer_head * bh;
 165         char * p;
 166 
 167         if (!inode) {
 168                 printk("minix_file_write: inode = NULL\n");
 169                 return -EINVAL;
 170         }
 171         if (!S_ISREG(inode->i_mode)) {
 172                 printk("minix_file_write: mode = %07o\n",inode->i_mode);
 173                 return -EINVAL;
 174         }
 175 /*
 176  * ok, append may not work when many processes are writing at the same time
 177  * but so what. That way leads to madness anyway.
 178  */
 179         if (filp->f_flags & O_APPEND)
 180                 pos = inode->i_size;
 181         else
 182                 pos = filp->f_pos;
 183         written = 0;
 184         while (written<count) {
 185                 if (!(block = minix_create_block(inode,pos/BLOCK_SIZE))) {
 186                         if (!written)
 187                                 written = -ENOSPC;
 188                         break;
 189                 }
 190                 c = BLOCK_SIZE - (pos % BLOCK_SIZE);
 191                 if (c > count-written)
 192                         c = count-written;
 193                 if (c == BLOCK_SIZE)
 194                         bh = getblk(inode->i_dev, block, BLOCK_SIZE);
 195                 else
 196                         bh = bread(inode->i_dev,block, BLOCK_SIZE);
 197                 if (!bh) {
 198                         if (!written)
 199                                 written = -EIO;
 200                         break;
 201                 }
 202                 p = (pos % BLOCK_SIZE) + bh->b_data;
 203                 pos += c;
 204                 if (pos > inode->i_size) {
 205                         inode->i_size = pos;
 206                         inode->i_dirt = 1;
 207                 }
 208                 written += c;
 209                 memcpy_fromfs(p,buf,c);
 210                 buf += c;
 211                 bh->b_uptodate = 1;
 212                 bh->b_dirt = 1;
 213                 brelse(bh);
 214         }
 215         inode->i_mtime = CURRENT_TIME;
 216         inode->i_ctime = CURRENT_TIME;
 217         filp->f_pos = pos;
 218         inode->i_dirt = 1;
 219         return written;
 220 }

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