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

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