home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / fs / nfs / file.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-23  |  5.7 KB  |  242 lines

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