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 
  25 #include <asm/segment.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 *, const 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_user(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                 inode->i_dirt = 1;
 195         }
 196         return read;
 197 }
 198 
 199 static int sysv_file_write(struct inode * inode, struct file * filp, const char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 200 {
 201         struct super_block * sb = inode->i_sb;
 202         off_t pos;
 203         int written,c;
 204         struct buffer_head * bh;
 205         char * p;
 206 
 207         if (!inode) {
 208                 printk("sysv_file_write: inode = NULL\n");
 209                 return -EINVAL;
 210         }
 211         if (!S_ISREG(inode->i_mode)) {
 212                 printk("sysv_file_write: mode = %07o\n",inode->i_mode);
 213                 return -EINVAL;
 214         }
 215 /*
 216  * ok, append may not work when many processes are writing at the same time
 217  * but so what. That way leads to madness anyway.
 218  * But we need to protect against simultaneous truncate as we may end up
 219  * writing our data into blocks that have meanwhile been incorporated into
 220  * the freelist, thereby trashing the freelist.
 221  */
 222         if (filp->f_flags & O_APPEND)
 223                 pos = inode->i_size;
 224         else
 225                 pos = filp->f_pos;
 226         written = 0;
 227         while (written<count) {
 228                 bh = sysv_getblk (inode, pos >> sb->sv_block_size_bits, 1);
 229                 if (!bh) {
 230                         if (!written)
 231                                 written = -ENOSPC;
 232                         break;
 233                 }
 234                 c = sb->sv_block_size - (pos & sb->sv_block_size_1);
 235                 if (c > count-written)
 236                         c = count-written;
 237                 if (c != sb->sv_block_size && !bh->b_uptodate) {
 238                         ll_rw_block(READ, 1, &bh);
 239                         wait_on_buffer(bh);
 240                         if (!bh->b_uptodate) {
 241                                 brelse(bh);
 242                                 if (!written)
 243                                         written = -EIO;
 244                                 break;
 245                         }
 246                 }
 247                 /* now either c==sb->sv_block_size or bh->b_uptodate */
 248                 p = (pos & sb->sv_block_size_1) + bh->b_data;
 249                 pos += c;
 250                 if (pos > inode->i_size) {
 251                         inode->i_size = pos;
 252                         inode->i_dirt = 1;
 253                 }
 254                 written += c;
 255                 memcpy_fromfs(p,buf,c);
 256                 buf += c;
 257                 bh->b_uptodate = 1;
 258                 mark_buffer_dirty(bh, 0);
 259                 brelse(bh);
 260         }
 261         inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 262         filp->f_pos = pos;
 263         inode->i_dirt = 1;
 264         return written;
 265 }

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