root/fs/sysv/file.c

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

DEFINITIONS

This source file includes following definitions.
  1. sysv_file_read
  2. sysv_file_write

   1 /*
   2  *  linux/fs/sysv/file.c
   3  *
   4  *  minix/file.c
   5  *  Copyright (C) 1991, 1992  Linus Torvalds
   6  *
   7  *  coh/file.c
   8  *  Copyright (C) 1993  Pascal Haible, Bruno Haible
   9  *
  10  *  sysv/file.c
  11  *  Copyright (C) 1993  Bruno Haible
  12  *
  13  *  SystemV/Coherent regular file handling primitives
  14  */
  15 
  16 #include <asm/segment.h>
  17 
  18 #include <linux/kernel.h>
  19 #include <linux/fs.h>
  20 #include <linux/sysv_fs.h>
  21 #include <linux/errno.h>
  22 #include <linux/fcntl.h>
  23 #include <linux/stat.h>
  24 #include <linux/string.h>
  25 #include <linux/locks.h>
  26 
  27 #define NBUF    32
  28 
  29 #define MIN(a,b) (((a)<(b))?(a):(b))
  30 #define MAX(a,b) (((a)>(b))?(a):(b))
  31 
  32 #include <linux/fs.h>
  33 #include <linux/sysv_fs.h>
  34 
  35 static int sysv_file_write(struct inode *, struct file *, char *, int);
  36 
  37 /*
  38  * We have mostly NULL's here: the current defaults are ok for
  39  * the coh filesystem.
  40  */
  41 static struct file_operations sysv_file_operations = {
  42         NULL,                   /* lseek - default */
  43         sysv_file_read,         /* read */
  44         sysv_file_write,        /* write */
  45         NULL,                   /* readdir - bad */
  46         NULL,                   /* select - default */
  47         NULL,                   /* ioctl - default */
  48         sysv_mmap,              /* mmap */
  49         NULL,                   /* no special open is needed */
  50         NULL,                   /* release */
  51         sysv_sync_file          /* fsync */
  52 };
  53 
  54 static struct file_operations sysv_file_operations_with_bmap = {
  55         NULL,                   /* lseek - default */
  56         sysv_file_read,         /* read */
  57         sysv_file_write,        /* write */
  58         NULL,                   /* readdir - bad */
  59         NULL,                   /* select - default */
  60         NULL,                   /* ioctl - default */
  61         generic_mmap,           /* mmap */
  62         NULL,                   /* no special open is needed */
  63         NULL,                   /* release */
  64         sysv_sync_file          /* fsync */
  65 };
  66 
  67 struct inode_operations sysv_file_inode_operations = {
  68         &sysv_file_operations,  /* default file operations */
  69         NULL,                   /* create */
  70         NULL,                   /* lookup */
  71         NULL,                   /* link */
  72         NULL,                   /* unlink */
  73         NULL,                   /* symlink */
  74         NULL,                   /* mkdir */
  75         NULL,                   /* rmdir */
  76         NULL,                   /* mknod */
  77         NULL,                   /* rename */
  78         NULL,                   /* readlink */
  79         NULL,                   /* follow_link */
  80         NULL,                   /* bmap */
  81         sysv_truncate,          /* truncate */
  82         NULL                    /* permission */
  83 };
  84 
  85 struct inode_operations sysv_file_inode_operations_with_bmap = {
  86         &sysv_file_operations_with_bmap, /* default file operations */
  87         NULL,                   /* create */
  88         NULL,                   /* lookup */
  89         NULL,                   /* link */
  90         NULL,                   /* unlink */
  91         NULL,                   /* symlink */
  92         NULL,                   /* mkdir */
  93         NULL,                   /* rmdir */
  94         NULL,                   /* mknod */
  95         NULL,                   /* rename */
  96         NULL,                   /* readlink */
  97         NULL,                   /* follow_link */
  98         sysv_bmap,              /* bmap */
  99         sysv_truncate,          /* truncate */
 100         NULL                    /* permission */
 101 };
 102 
 103 struct sysv_buffer {
 104         struct buffer_head * bh;
 105         char * bh_data;
 106 };
 107 
 108 int sysv_file_read(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 109 {
 110         struct super_block * sb = inode->i_sb;
 111         int read,left,chars;
 112         unsigned int block;
 113         int blocks, offset;
 114         int bhrequest, bhreqi, uptodate;
 115         struct sysv_buffer * bhb, * bhe;
 116         struct buffer_head * bhreq[NBUF];
 117         struct sysv_buffer buflist[NBUF];
 118         unsigned int size;
 119 
 120         if (!inode) {
 121                 printk("sysv_file_read: inode = NULL\n");
 122                 return -EINVAL;
 123         }
 124         if (!S_ISREG(inode->i_mode)) {
 125                 printk("sysv_file_read: mode = %07o\n",inode->i_mode);
 126                 return -EINVAL;
 127         }
 128         offset = filp->f_pos;
 129         size = inode->i_size;
 130         if (offset > size)
 131                 left = 0;
 132         else
 133                 left = size - offset;
 134         if (left > count)
 135                 left = count;
 136         if (left <= 0)
 137                 return 0;
 138         read = 0;
 139         block = offset >> sb->sv_block_size_bits;
 140         offset &= sb->sv_block_size_1;
 141         size = (size + sb->sv_block_size_1) >> sb->sv_block_size_bits;
 142         blocks = (left + offset + sb->sv_block_size_1) >> sb->sv_block_size_bits;
 143         bhb = bhe = buflist;
 144         if (filp->f_reada) {
 145                 blocks += read_ahead[MAJOR(inode->i_dev)] >> (sb->sv_block_size_bits - 9);
 146                 if (block + blocks > size)
 147                         blocks = size - block;
 148         }
 149 
 150         /* We do this in a two stage process.  We first try and request
 151            as many blocks as we can, then we wait for the first one to
 152            complete, and then we try and wrap up as many as are actually
 153            done.  This routine is rather generic, in that it can be used
 154            in a filesystem by substituting the appropriate function in
 155            for getblk.
 156 
 157            This routine is optimized to make maximum use of the various
 158            buffers and caches.
 159 
 160            We must remove duplicates from the bhreq array as ll_rw_block
 161            doesn't like duplicate requests (it hangs in wait_on_buffer...).
 162          */
 163 
 164         do {
 165                 bhrequest = 0;
 166                 uptodate = 1;
 167                 while (blocks) {
 168                         --blocks;
 169                         bhb->bh = sysv_getblk(inode, block++, 0, &bhb->bh_data);
 170                         if (bhb->bh && !bhb->bh->b_uptodate) {
 171                                 uptodate = 0;
 172                                 if (sb->sv_block_size_ratio_bits > 0) /* block_size < BLOCK_SIZE ? */
 173                                         for (bhreqi = 0; bhreqi < bhrequest; bhreqi++)
 174                                                 if (bhreq[bhreqi] == bhb->bh)
 175                                                         goto notreq;
 176                                 bhreq[bhrequest++] = bhb->bh;
 177                                 notreq: ;
 178                         }
 179 
 180                         if (++bhb == &buflist[NBUF])
 181                                 bhb = buflist;
 182 
 183                         /* If the block we have on hand is uptodate, go ahead
 184                            and complete processing. */
 185                         if (uptodate)
 186                                 break;
 187                         if (bhb == bhe)
 188                                 break;
 189                 }
 190 
 191                 /* Now request them all */
 192                 if (bhrequest)
 193                         ll_rw_block(READ, bhrequest, bhreq);
 194 
 195                 do { /* Finish off all I/O that has actually completed */
 196                         if (bhe->bh) {
 197                                 wait_on_buffer(bhe->bh);
 198                                 if (!bhe->bh->b_uptodate) {     /* read error? */
 199                                         brelse(bhe->bh);
 200                                         if (++bhe == &buflist[NBUF])
 201                                                 bhe = buflist;
 202                                         left = 0;
 203                                         break;
 204                                 }
 205                         }
 206                         if (left < sb->sv_block_size - offset)
 207                                 chars = left;
 208                         else
 209                                 chars = sb->sv_block_size - offset;
 210                         filp->f_pos += chars;
 211                         left -= chars;
 212                         read += chars;
 213                         if (bhe->bh) {
 214                                 memcpy_tofs(buf,offset+bhe->bh_data,chars);
 215                                 brelse(bhe->bh);
 216                                 buf += chars;
 217                         } else {
 218                                 while (chars-- > 0)
 219                                         put_fs_byte(0,buf++);
 220                         }
 221                         offset = 0;
 222                         if (++bhe == &buflist[NBUF])
 223                                 bhe = buflist;
 224                 } while (left > 0 && bhe != bhb && (!bhe->bh || !bhe->bh->b_lock));
 225         } while (left > 0);
 226 
 227 /* Release the read-ahead blocks */
 228         while (bhe != bhb) {
 229                 brelse(bhe->bh);
 230                 if (++bhe == &buflist[NBUF])
 231                         bhe = buflist;
 232         };
 233         if (!read)
 234                 return -EIO;
 235         filp->f_reada = 1;
 236         if (!IS_RDONLY(inode))
 237                 inode->i_atime = CURRENT_TIME;
 238         return read;
 239 }
 240 
 241 static int sysv_file_write(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 242 {
 243         struct super_block * sb = inode->i_sb;
 244         off_t pos;
 245         int written,c;
 246         struct buffer_head * bh;
 247         char * bh_data;
 248         char * p;
 249 
 250         if (!inode) {
 251                 printk("sysv_file_write: inode = NULL\n");
 252                 return -EINVAL;
 253         }
 254         if (!S_ISREG(inode->i_mode)) {
 255                 printk("sysv_file_write: mode = %07o\n",inode->i_mode);
 256                 return -EINVAL;
 257         }
 258 /*
 259  * ok, append may not work when many processes are writing at the same time
 260  * but so what. That way leads to madness anyway.
 261  * But we need to protect against simultaneous truncate as we may end up
 262  * writing our data into blocks that have meanwhile been incorporated into
 263  * the freelist, thereby trashing the freelist.
 264  */
 265         if (sb->sv_block_size_ratio_bits > 0) /* block_size < BLOCK_SIZE ? */
 266                 coh_lock_inode(inode);
 267         if (filp->f_flags & O_APPEND)
 268                 pos = inode->i_size;
 269         else
 270                 pos = filp->f_pos;
 271         written = 0;
 272         while (written<count) {
 273                 bh = sysv_getblk (inode, pos >> sb->sv_block_size_bits, 1, &bh_data);
 274                 if (!bh) {
 275                         if (!written)
 276                                 written = -ENOSPC;
 277                         break;
 278                 }
 279                 c = sb->sv_block_size - (pos & sb->sv_block_size_1);
 280                 if (c > count-written)
 281                         c = count-written;
 282                 if (c != BLOCK_SIZE && !bh->b_uptodate) {
 283                         ll_rw_block(READ, 1, &bh);
 284                         wait_on_buffer(bh);
 285                         if (!bh->b_uptodate) {
 286                                 brelse(bh);
 287                                 if (!written)
 288                                         written = -EIO;
 289                                 break;
 290                         }
 291                 }
 292                 /* now either c==BLOCK_SIZE or bh->b_uptodate */
 293                 p = (pos & sb->sv_block_size_1) + bh_data;
 294                 pos += c;
 295                 if (pos > inode->i_size) {
 296                         inode->i_size = pos;
 297                         inode->i_dirt = 1;
 298                 }
 299                 written += c;
 300                 memcpy_fromfs(p,buf,c);
 301                 buf += c;
 302                 bh->b_uptodate = 1;
 303                 mark_buffer_dirty(bh, 0);
 304                 brelse(bh);
 305         }
 306         inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 307         filp->f_pos = pos;
 308         inode->i_dirt = 1;
 309         if (sb->sv_block_size_ratio_bits > 0) /* block_size < BLOCK_SIZE ? */
 310                 coh_unlock_inode(inode);
 311         return written;
 312 }

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