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

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