root/fs/nfs/file.c

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

DEFINITIONS

This source file includes following definitions.
  1. nfs_fsync
  2. nfs_file_read
  3. nfs_file_write

   1 /*
   2  *  linux/fs/nfs/file.c
   3  *
   4  *  Copyright (C) 1992  Rick Sladkey
   5  *
   6  *  Changes Copyright (C) 1994 by Florian La Roche
   7  *   - Do not copy data too often around in the kernel.
   8  *   - In nfs_file_read the return value of kmalloc wasn't checked.
   9  *   - Put in a better version of read look-ahead buffering. Original idea
  10  *     and implementation by Wai S Kok elekokws@ee.nus.sg.
  11  *
  12  *  Expire cache on write to a file by Wai S Kok (Oct 1994).
  13  *
  14  *  nfs regular file handling functions
  15  */
  16 
  17 #include <asm/segment.h>
  18 #include <asm/system.h>
  19 
  20 #include <linux/sched.h>
  21 #include <linux/kernel.h>
  22 #include <linux/errno.h>
  23 #include <linux/fcntl.h>
  24 #include <linux/stat.h>
  25 #include <linux/mm.h>
  26 #include <linux/nfs_fs.h>
  27 #include <linux/malloc.h>
  28 
  29 static int nfs_file_read(struct inode *, struct file *, char *, int);
  30 static int nfs_file_write(struct inode *, struct file *, char *, int);
  31 static int nfs_fsync(struct inode *, struct file *);
  32 
  33 static struct file_operations nfs_file_operations = {
  34         NULL,                   /* lseek - default */
  35         nfs_file_read,          /* read */
  36         nfs_file_write,         /* write */
  37         NULL,                   /* readdir - bad */
  38         NULL,                   /* select - default */
  39         NULL,                   /* ioctl - default */
  40         nfs_mmap,               /* mmap */
  41         NULL,                   /* no special open is needed */
  42         NULL,                   /* release */
  43         nfs_fsync,              /* fsync */
  44 };
  45 
  46 struct inode_operations nfs_file_inode_operations = {
  47         &nfs_file_operations,   /* default file operations */
  48         NULL,                   /* create */
  49         NULL,                   /* lookup */
  50         NULL,                   /* link */
  51         NULL,                   /* unlink */
  52         NULL,                   /* symlink */
  53         NULL,                   /* mkdir */
  54         NULL,                   /* rmdir */
  55         NULL,                   /* mknod */
  56         NULL,                   /* rename */
  57         NULL,                   /* readlink */
  58         NULL,                   /* follow_link */
  59         NULL,                   /* bmap */
  60         NULL                    /* truncate */
  61 };
  62 
  63 /* Once data is inserted, it can only be deleted, if (in_use==0). */
  64 struct read_cache {
  65         int             in_use;         /* currently in use? */
  66         unsigned long   inode_num;      /* inode number */
  67         off_t           file_pos;       /* file position */
  68         int             len;            /* size of data */
  69         unsigned long   time;           /* time, this entry was inserted */
  70         char *          buf;            /* data */
  71         int             buf_size;       /* size of buffer */
  72 };
  73 
  74 #define READ_CACHE_SIZE 5
  75 #define EXPIRE_CACHE (HZ * 3)           /* keep no longer than 3 seconds */
  76 
  77 unsigned long num_requests = 0;
  78 unsigned long num_cache_hits = 0;
  79 
  80 static int tail = 0;    /* next cache slot to replace */
  81 
  82 static struct read_cache cache[READ_CACHE_SIZE] = {
  83         { 0, 0, -1, 0, 0, NULL, 0 },
  84         { 0, 0, -1, 0, 0, NULL, 0 },
  85         { 0, 0, -1, 0, 0, NULL, 0 },
  86         { 0, 0, -1, 0, 0, NULL, 0 },
  87         { 0, 0, -1, 0, 0, NULL, 0 } };
  88 
  89 static int nfs_fsync(struct inode *inode, struct file *file)
     /* [previous][next][first][last][top][bottom][index][help] */
  90 {
  91         return 0;
  92 }
  93 
  94 static int nfs_file_read(struct inode *inode, struct file *file, char *buf,
     /* [previous][next][first][last][top][bottom][index][help] */
  95                          int count)
  96 {
  97         int result, hunk, i, n, fs;
  98         struct nfs_fattr fattr;
  99         char *data;
 100         off_t pos;
 101 
 102         if (!inode) {
 103                 printk("nfs_file_read: inode = NULL\n");
 104                 return -EINVAL;
 105         }
 106         if (!S_ISREG(inode->i_mode)) {
 107                 printk("nfs_file_read: read from non-file, mode %07o\n",
 108                         inode->i_mode);
 109                 return -EINVAL;
 110         }
 111         pos = file->f_pos;
 112         if (pos + count > inode->i_size)
 113                 count = inode->i_size - pos;
 114         if (count <= 0)
 115                 return 0;
 116         ++num_requests;
 117         cli();
 118         for (i = 0; i < READ_CACHE_SIZE; i++)
 119                 if ((cache[i].inode_num == inode->i_ino)
 120                         && (cache[i].file_pos <= pos)
 121                         && (cache[i].file_pos + cache[i].len >= pos + count)
 122                         && (abs(jiffies - cache[i].time) <= EXPIRE_CACHE))
 123                         break;
 124         if (i < READ_CACHE_SIZE) {
 125                 ++cache[i].in_use;
 126                 sti();
 127                 ++num_cache_hits;
 128                 memcpy_tofs(buf, cache[i].buf + pos - cache[i].file_pos, count);
 129                 --cache[i].in_use;
 130                 file->f_pos += count;
 131                 return count;
 132         }
 133         sti();
 134         n = NFS_SERVER(inode)->rsize;
 135         for (i = 0; i < count - n; i += n) {
 136                 result = nfs_proc_read(NFS_SERVER(inode), NFS_FH(inode), 
 137                         pos, n, buf, &fattr, 1);
 138                 if (result < 0)
 139                         return result;
 140                 pos += result;
 141                 buf += result;
 142                 if (result < n) {
 143                         file->f_pos = pos;
 144                         nfs_refresh_inode(inode, &fattr);
 145                         return i + result;
 146                 }
 147         }
 148         fs = 0;
 149         if (!(data = (char *)kmalloc(n, GFP_KERNEL))) {
 150                 data = buf;
 151                 fs = 1;
 152         }
 153         result = nfs_proc_read(NFS_SERVER(inode), NFS_FH(inode),
 154                 pos, n, data, &fattr, fs);
 155         if (result < 0) {
 156                 if (!fs)
 157                         kfree_s(data, n);
 158                 return result;
 159         }
 160         hunk = count - i;
 161         if (result < hunk)
 162                 hunk = result;
 163         if (fs) {
 164                 file->f_pos = pos + hunk;
 165                 nfs_refresh_inode(inode, &fattr);
 166                 return i + hunk;
 167         }
 168         memcpy_tofs(buf, data, hunk);
 169         file->f_pos = pos + hunk;
 170         nfs_refresh_inode(inode, &fattr);
 171         cli();
 172         if (cache[tail].in_use == 0) {
 173                 if (cache[tail].buf)
 174                         kfree_s(cache[tail].buf, cache[tail].buf_size);
 175                 cache[tail].buf = data;
 176                 cache[tail].buf_size = n;
 177                 cache[tail].inode_num = inode->i_ino;
 178                 cache[tail].file_pos = pos;
 179                 cache[tail].len = result;
 180                 cache[tail].time = jiffies;
 181                 if (++tail >= READ_CACHE_SIZE)
 182                         tail = 0;
 183         } else
 184                 kfree_s(data, n);
 185         sti();
 186         return i + hunk;
 187 }
 188 
 189 static int nfs_file_write(struct inode *inode, struct file *file, char *buf,
     /* [previous][next][first][last][top][bottom][index][help] */
 190                           int count)
 191 {
 192         int result, hunk, i, n, pos;
 193         struct nfs_fattr fattr;
 194 
 195         if (!inode) {
 196                 printk("nfs_file_write: inode = NULL\n");
 197                 return -EINVAL;
 198         }
 199         if (!S_ISREG(inode->i_mode)) {
 200                 printk("nfs_file_write: write to non-file, mode %07o\n",
 201                         inode->i_mode);
 202                 return -EINVAL;
 203         }
 204         if (count <= 0)
 205                 return 0;
 206 
 207         cli();
 208         /* If hit, cache is dirty and must be expired. */
 209         for (i = 0; i < READ_CACHE_SIZE; i++)
 210                 if(cache[i].inode_num == inode->i_ino)
 211                         cache[i].time -= EXPIRE_CACHE;
 212         sti();
 213 
 214         pos = file->f_pos;
 215         if (file->f_flags & O_APPEND)
 216                 pos = inode->i_size;
 217         n = NFS_SERVER(inode)->wsize;
 218         for (i = 0; i < count; i += n) {
 219                 hunk = count - i;
 220                 if (hunk >= n)
 221                         hunk = n;
 222                 result = nfs_proc_write(NFS_SERVER(inode), NFS_FH(inode), 
 223                         pos, hunk, buf, &fattr);
 224                 if (result < 0)
 225                         return result;
 226                 pos += hunk;
 227                 buf += hunk;
 228                 if (hunk < n) {
 229                         i += hunk;
 230                         break;
 231                 }
 232         }
 233         file->f_pos = pos;
 234         nfs_refresh_inode(inode, &fattr);
 235         return i;
 236 }
 237 

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