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

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