support-reiserfs-20010129
[openafs.git] / src / afs / LINUX / osi_vnodeops.c
index 1c45181..e322a9f 100644 (file)
 #include "../h/smp_lock.h"
 #endif
 
+#ifdef pgoff2loff
+#define pageoff(pp) pgoff2loff((pp)->index)
+#else
+#define pageoff(pp) pp->offset
+#endif
+
 extern struct vcache *afs_globalVp;
 
 extern struct dentry_operations *afs_dops;
@@ -146,6 +152,7 @@ static ssize_t afs_linux_write(struct file *fp, const char *buf, size_t count,
 static int afs_linux_readdir(struct file *fp,
                             void *dirbuf, filldir_t filldir)
 {
+    extern struct DirEntry * afs_dir_GetBlob();
     struct vcache *avc = (struct vcache*)FILE_INODE(fp);
     struct vrequest treq;
     register struct dcache *tdc;
@@ -223,8 +230,11 @@ tagain:
        len = strlen(de->name);
 
        /* filldir returns -EINVAL when the buffer is full. */
-       /* code = (*filldir)(dirbuf, de->name, len, offset, ino); */
+#ifdef AFS_LINUX24_ENV
        code = (*filldir)(dirbuf, de->name, len, offset, ino, DT_DIR);
+#else
+       code = (*filldir)(dirbuf, de->name, len, offset, ino); 
+#endif
        DRelease(de, 0);
        if (code)
            break;
@@ -522,7 +532,7 @@ int afs_linux_flush(struct file *fp)
 }
 
 /* Not allowed to directly read a directory. */
-int afs_linux_dir_read(struct file *fp, char *buf, size_t count, loff_t *ppos)
+ssize_t afs_linux_dir_read(struct file *fp, char *buf, size_t count, loff_t *ppos)
 {
     return -EISDIR;
 }
@@ -1073,6 +1083,7 @@ struct dentry * afs_linux_follow_link(struct dentry *dp,
 {
     int code = 0;
     char *name;
+    struct dentry *res;
 
     AFS_GLOCK();
     name = osi_Alloc(PATH_MAX+1);
@@ -1099,6 +1110,7 @@ struct dentry * afs_linux_follow_link(struct dentry *dp,
     AFS_GUNLOCK();
     return res;
 }
+#endif
 
 /* afs_linux_readpage
  * all reads come through here. A strategy-like read call.
@@ -1120,14 +1132,18 @@ int afs_linux_readpage(struct file *fp, struct page *pp)
               ICL_TYPE_INT32, cnt,
               ICL_TYPE_INT32, 99999); /* not a possible code value */
     atomic_add(1, &pp->count);
+#if defined(AFS_LINUX24_ENV)
+    ClearPageError(pp);
+#else
     set_bit(PG_locked, &pp->flags); /* other bits? See mm.h */
     clear_bit(PG_error, &pp->flags);
+#endif
 
 #if defined(AFS_LINUX24_ENV)
     setup_uio(&tuio, &iovec, (char*)address, pp->index << PAGE_CACHE_SHIFT,
              PAGESIZE, UIO_READ, AFS_UIOSYS);
 #else
-    setup_uio(&tuio, &iovec, (char*)address, pp->offset, PAGESIZE,
+    setup_uio(&tuio, &iovec, (char*)address, pageoff(pp), PAGESIZE,
              UIO_READ, AFS_UIOSYS);
 #endif
 #ifdef AFS_LINUX24_ENV
@@ -1142,10 +1158,18 @@ int afs_linux_readpage(struct file *fp, struct page *pp)
        if (tuio.uio_resid) /* zero remainder of page */
            memset((void*)(address+(PAGESIZE-tuio.uio_resid)), 0,
                   tuio.uio_resid);
+#if defined(AFS_LINUX24_ENV)
+        SetPageUptodate(pp);
+#else
        set_bit(PG_uptodate, &pp->flags);
+#endif
     }
 
+#if defined(AFS_LINUX24_ENV)
+    UnlockPage(pp);
+#else
     clear_bit(PG_locked, &pp->flags);
+#endif
     wake_up(&pp->wait);
     free_page(address);
 
@@ -1159,10 +1183,39 @@ int afs_linux_readpage(struct file *fp, struct page *pp)
     return -code;
 }
 
-#ifdef NOTUSED
-/* afs_linux_writepage - is this used anywhere? swap files via nfs? */
-int afs_linux_writepage(struct inode *ip, struct page *) { return -EINVAL };
+#if defined(AFS_LINUX24_ENV)
+int afs_linux_writepage(struct page *pp)
+{
+    struct address_space *mapping = pp->mapping;
+    struct inode *inode;
+    unsigned long end_index;
+    unsigned offset = PAGE_CACHE_SIZE;
+    long status;
+    inode = (struct inode *) mapping->host;
+    end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+
+    /* easy case */
+    if (pp->index < end_index)
+       goto do_it;
+    /* things got complicated... */
+    offset = inode->i_size & (PAGE_CACHE_SIZE-1);
+    /* OK, are we completely out? */
+    if (pp->index >= end_index+1 || !offset)
+       return -EIO;
+do_it:
+    status = afs_linux_writepage_sync(inode, pp, 0, offset);
+    SetPageUptodate(pp);
+    UnlockPage(pp);
+    /* kunmap(pp); */
+    if (status == offset)
+       return 0;
+    else
+       return status;
+}
+#endif
 
+#ifdef NOTUSED
 /* afs_linux_bmap - supports generic_readpage, but we roll our own. */
 int afs_linux_bmap(struct inode *ip, int) { return -EINVAL; }
 
@@ -1201,6 +1254,56 @@ int afs_linux_permission(struct inode *ip, int mode)
 int afs_linux_smap(struct inode *ip, int) { return -EINVAL; }
 #endif
 
+#if defined(AFS_LINUX24_ENV)
+int afs_linux_writepage_sync(struct inode *ip, struct page *pp,
+                        unsigned long offset,
+                        unsigned int count)
+{
+    struct vcache *vcp = (struct vcache *) ip;
+    u8 *page_addr = (u8*) afs_linux_page_address(pp);
+    int code = 0;
+    cred_t *credp;
+    uio_t tuio;
+    struct iovec iovec;
+    int f_flags = 0;
+
+    credp = crref();
+    AFS_GLOCK();
+    lock_kernel();
+    afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp,
+              ICL_TYPE_POINTER, pp,
+              ICL_TYPE_INT32, atomic_read(&pp->count),
+              ICL_TYPE_INT32, 99999);
+    setup_uio(&tuio, &iovec, page_addr + offset,
+             (pp->index << PAGE_CACHE_SHIFT) + offset, count,
+             UIO_WRITE, AFS_UIOSYS);
+
+    code = afs_write(vcp, &tuio, f_flags, credp, 0);
+
+    vcache2inode(vcp);
+
+    code = code ? -code : count - tuio.uio_resid;
+    afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp,
+              ICL_TYPE_POINTER, pp,
+              ICL_TYPE_INT32, atomic_read(&pp->count),
+              ICL_TYPE_INT32, code);
+
+    unlock_kernel();
+    AFS_GUNLOCK();
+    crfree(credp);
+
+    return code;
+}
+
+static int
+afs_linux_updatepage(struct file *file, struct page *page, 
+                    unsigned long offset, unsigned int count)
+{
+    struct dentry *dentry = file->f_dentry;
+
+    return afs_linux_writepage_sync(dentry->d_inode, page, offset, count);
+}
+#else
 /* afs_linux_updatepage
  * What one would have thought was writepage - write dirty page to file.
  * Called from generic_file_write. buffer is still in user space. pagep
@@ -1221,21 +1324,12 @@ int afs_linux_updatepage(struct file *fp, struct page *pp,
 
     credp = crref();
     AFS_GLOCK();
-#ifdef AFS_LINUX24_ENV
-    lock_kernel();
-#endif
     afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp,
               ICL_TYPE_POINTER, pp,
               ICL_TYPE_INT32, atomic_read(&pp->count),
               ICL_TYPE_INT32, 99999);
-#if defined(AFS_LINUX24_ENV)
-    setup_uio(&tuio, &iovec, page_addr + offset,
-             (pp->index << PAGE_CACHE_SHIFT) + offset, count,
-             UIO_WRITE, AFS_UIOSYS);
-#else
-    setup_uio(&tuio, &iovec, page_addr + offset, pp->offset + offset, count,
+    setup_uio(&tuio, &iovec, page_addr + offset, pageoff(pp) + offset, count,
              UIO_WRITE, AFS_UIOSYS);
-#endif
 
     code = afs_write(vcp, &tuio, fp->f_flags, credp, 0);
 
@@ -1247,23 +1341,22 @@ int afs_linux_updatepage(struct file *fp, struct page *pp,
               ICL_TYPE_INT32, atomic_read(&pp->count),
               ICL_TYPE_INT32, code);
 
-#ifdef AFS_LINUX24_ENV
-    unlock_kernel();
-#endif
     AFS_GUNLOCK();
     crfree(credp);
 
     clear_bit(PG_locked, &pp->flags);
     return code;
 }
+#endif
 
 #if defined(AFS_LINUX24_ENV)
 static int afs_linux_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to)
 {
     long status;
-    loff_t pos = ((loff_t)page->index<<PAGE_CACHE_SHIFT) + to;
 
-    status = afs_linux_updatepage(file, page, offset, to-offset, 1);
+    /* lock_kernel(); */
+    status = afs_linux_updatepage(file, page, offset, to-offset);
+    /* unlock_kernel(); */
     kunmap(page);
 
     return status;
@@ -1287,6 +1380,7 @@ struct inode_operations afs_file_iops = {
 };
 struct address_space_operations afs_file_aops = {
         readpage: afs_linux_readpage,
+        writepage: afs_linux_writepage,
         commit_write: afs_linux_commit_write,
         prepare_write: afs_linux_prepare_write,
 };