linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / fs / afs / file.c
index e8e3680..150b192 100644 (file)
 #include <linux/slab.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
-#include <linux/pagevec.h>
 #include <linux/buffer_head.h>
 #include "volume.h"
 #include "vnode.h"
 #include <rxrpc/call.h>
 #include "internal.h"
 
-#define list_to_page(head) (list_entry((head)->prev, struct page, lru))
-
 #if 0
 static int afs_file_open(struct inode *inode, struct file *file);
 static int afs_file_release(struct inode *inode, struct file *file);
 #endif
 
 static int afs_file_readpage(struct file *file, struct page *page);
-static void afs_file_invalidatepage(struct page *page, unsigned long offset);
+static int afs_file_invalidatepage(struct page *page, unsigned long offset);
 static int afs_file_releasepage(struct page *page, gfp_t gfp_flags);
-static int afs_file_mmap(struct file * file, struct vm_area_struct * vma);
-
-#ifdef CONFIG_AFS_FSCACHE
-static int afs_file_readpages(struct file *filp, struct address_space *mapping,
-                             struct list_head *pages, unsigned nr_pages);
-static int afs_file_page_mkwrite(struct vm_area_struct *vma, struct page *page);
-#endif
 
 struct inode_operations afs_file_inode_operations = {
        .getattr        = afs_inode_getattr,
 };
 
-const struct file_operations afs_file_file_operations = {
-       .llseek         = generic_file_llseek,
-       .read           = generic_file_read,
-       .mmap           = afs_file_mmap,
-       .sendfile       = generic_file_sendfile,
-};
-
-const struct address_space_operations afs_fs_aops = {
+struct address_space_operations afs_fs_aops = {
        .readpage       = afs_file_readpage,
-#ifdef CONFIG_AFS_FSCACHE
-       .readpages      = afs_file_readpages,
-#endif
        .sync_page      = block_sync_page,
        .set_page_dirty = __set_page_dirty_nobuffers,
        .releasepage    = afs_file_releasepage,
        .invalidatepage = afs_file_invalidatepage,
 };
 
-static struct vm_operations_struct afs_fs_vm_operations = {
-       .nopage         = filemap_nopage,
-       .populate       = filemap_populate,
-#ifdef CONFIG_AFS_FSCACHE
-       .page_mkwrite   = afs_file_page_mkwrite,
-#endif
-};
-
-/*****************************************************************************/
-/*
- * set up a memory mapping on an AFS file
- * - we set our own VMA ops so that we can catch the page becoming writable for
- *   userspace for shared-writable mmap
- */
-static int afs_file_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       _enter("");
-
-       file_accessed(file);
-       vma->vm_ops = &afs_fs_vm_operations;
-       return 0;
-
-} /* end afs_file_mmap() */
-
 /*****************************************************************************/
 /*
  * deal with notification that a page was read from the cache
  */
-#ifdef CONFIG_AFS_FSCACHE
-static void afs_file_readpage_read_complete(struct page *page,
+#ifdef AFS_CACHING_SUPPORT
+static void afs_file_readpage_read_complete(void *cookie_data,
+                                           struct page *page,
                                            void *data,
                                            int error)
 {
-       _enter("%p,%p,%d", page, data, error);
+       _enter("%p,%p,%p,%d", cookie_data, page, data, error);
 
-       /* if the read completes with an error, we just unlock the page and let
-        * the VM reissue the readpage */
-       if (!error)
+       if (error)
+               SetPageError(page);
+       else
                SetPageUptodate(page);
        unlock_page(page);
 
@@ -111,16 +68,15 @@ static void afs_file_readpage_read_complete(struct page *page,
 /*
  * deal with notification that a page was written to the cache
  */
-#ifdef CONFIG_AFS_FSCACHE
-static void afs_file_readpage_write_complete(struct page *page,
+#ifdef AFS_CACHING_SUPPORT
+static void afs_file_readpage_write_complete(void *cookie_data,
+                                            struct page *page,
                                             void *data,
                                             int error)
 {
-       _enter("%p,%p,%d", page, data, error);
+       _enter("%p,%p,%p,%d", cookie_data, page, data, error);
 
-       /* note that the page has been written to the cache and can now be
-        * modified */
-       end_page_fs_misc(page);
+       unlock_page(page);
 
 } /* end afs_file_readpage_write_complete() */
 #endif
@@ -132,13 +88,16 @@ static void afs_file_readpage_write_complete(struct page *page,
 static int afs_file_readpage(struct file *file, struct page *page)
 {
        struct afs_rxfs_fetch_descriptor desc;
+#ifdef AFS_CACHING_SUPPORT
+       struct cachefs_page *pageio;
+#endif
        struct afs_vnode *vnode;
        struct inode *inode;
        int ret;
 
        inode = page->mapping->host;
 
-       _enter("{%lu},%p{%lu}", inode->i_ino, page, page->index);
+       _enter("{%lu},{%lu}", inode->i_ino, page->index);
 
        vnode = AFS_FS_I(inode);
 
@@ -148,9 +107,13 @@ static int afs_file_readpage(struct file *file, struct page *page)
        if (vnode->flags & AFS_VNODE_DELETED)
                goto error;
 
-#ifdef CONFIG_AFS_FSCACHE
+#ifdef AFS_CACHING_SUPPORT
+       ret = cachefs_page_get_private(page, &pageio, GFP_NOIO);
+       if (ret < 0)
+               goto error;
+
        /* is it cached? */
-       ret = fscache_read_or_alloc_page(vnode->cache,
+       ret = cachefs_read_or_alloc_page(vnode->cache,
                                         page,
                                         afs_file_readpage_read_complete,
                                         NULL,
@@ -160,20 +123,18 @@ static int afs_file_readpage(struct file *file, struct page *page)
 #endif
 
        switch (ret) {
+               /* read BIO submitted and wb-journal entry found */
+       case 1:
+               BUG(); // TODO - handle wb-journal match
+
                /* read BIO submitted (page in cache) */
        case 0:
                break;
 
-               /* page not yet cached */
-       case -ENODATA:
-               _debug("cache said ENODATA");
-               goto go_on;
-
-               /* page will not be cached */
+               /* no page available in cache */
        case -ENOBUFS:
-               _debug("cache said ENOBUFS");
+       case -ENODATA:
        default:
-       go_on:
                desc.fid        = vnode->fid;
                desc.offset     = page->index << PAGE_CACHE_SHIFT;
                desc.size       = min((size_t) (inode->i_size - desc.offset),
@@ -187,40 +148,34 @@ static int afs_file_readpage(struct file *file, struct page *page)
                ret = afs_vnode_fetch_data(vnode, &desc);
                kunmap(page);
                if (ret < 0) {
-                       if (ret == -ENOENT) {
-                               kdebug("got NOENT from server"
+                       if (ret==-ENOENT) {
+                               _debug("got NOENT from server"
                                       " - marking file deleted and stale");
                                vnode->flags |= AFS_VNODE_DELETED;
                                ret = -ESTALE;
                        }
 
-#ifdef CONFIG_AFS_FSCACHE
-                       fscache_uncache_page(vnode->cache, page);
-                       ClearPagePrivate(page);
+#ifdef AFS_CACHING_SUPPORT
+                       cachefs_uncache_page(vnode->cache, page);
 #endif
                        goto error;
                }
 
                SetPageUptodate(page);
 
-               /* send the page to the cache */
-#ifdef CONFIG_AFS_FSCACHE
-               if (PagePrivate(page)) {
-                       if (TestSetPageFsMisc(page))
-                               BUG();
-                       if (fscache_write_page(vnode->cache,
-                                              page,
-                                              afs_file_readpage_write_complete,
-                                              NULL,
-                                              GFP_KERNEL) != 0
-                           ) {
-                               fscache_uncache_page(vnode->cache, page);
-                               ClearPagePrivate(page);
-                               end_page_fs_misc(page);
-                       }
+#ifdef AFS_CACHING_SUPPORT
+               if (cachefs_write_page(vnode->cache,
+                                      page,
+                                      afs_file_readpage_write_complete,
+                                      NULL,
+                                      GFP_KERNEL) != 0
+                   ) {
+                       cachefs_uncache_page(vnode->cache, page);
+                       unlock_page(page);
                }
-#endif
+#else
                unlock_page(page);
+#endif
        }
 
        _leave(" = 0");
@@ -237,87 +192,57 @@ static int afs_file_readpage(struct file *file, struct page *page)
 
 /*****************************************************************************/
 /*
- * read a set of pages
+ * get a page cookie for the specified page
  */
-#ifdef CONFIG_AFS_FSCACHE
-static int afs_file_readpages(struct file *filp, struct address_space *mapping,
-                             struct list_head *pages, unsigned nr_pages)
+#ifdef AFS_CACHING_SUPPORT
+int afs_cache_get_page_cookie(struct page *page,
+                             struct cachefs_page **_page_cookie)
 {
-       struct afs_vnode *vnode;
-#if 0
-       struct pagevec lru_pvec;
-       unsigned page_idx;
-#endif
-       int ret = 0;
-
-       _enter(",{%lu},,%d", mapping->host->i_ino, nr_pages);
-
-       vnode = AFS_FS_I(mapping->host);
-       if (vnode->flags & AFS_VNODE_DELETED) {
-               _leave(" = -ESTALE");
-               return -ESTALE;
-       }
-
-       /* attempt to read as many of the pages as possible */
-       ret = fscache_read_or_alloc_pages(vnode->cache,
-                                         mapping,
-                                         pages,
-                                         &nr_pages,
-                                         afs_file_readpage_read_complete,
-                                         NULL,
-                                         mapping_gfp_mask(mapping));
-
-       switch (ret) {
-               /* all pages are being read from the cache */
-       case 0:
-               BUG_ON(!list_empty(pages));
-               BUG_ON(nr_pages != 0);
-               _leave(" = 0 [reading all]");
-               return 0;
-
-               /* there were pages that couldn't be read from the cache */
-       case -ENODATA:
-       case -ENOBUFS:
-               break;
-
-               /* other error */
-       default:
-               _leave(" = %d", ret);
-               return ret;
-       }
+       int ret;
 
-       /* load the missing pages from the network */
-       ret = read_cache_pages(mapping, pages,
-                              (void *) afs_file_readpage, NULL);
+       _enter("");
+       ret = cachefs_page_get_private(page,_page_cookie, GFP_NOIO);
 
-       _leave(" = %d [netting]", ret);
+       _leave(" = %d", ret);
        return ret;
-
-} /* end afs_file_readpages() */
+} /* end afs_cache_get_page_cookie() */
 #endif
 
 /*****************************************************************************/
 /*
  * invalidate part or all of a page
  */
-static void afs_file_invalidatepage(struct page *page, unsigned long offset)
+static int afs_file_invalidatepage(struct page *page, unsigned long offset)
 {
+       int ret = 1;
+
        _enter("{%lu},%lu", page->index, offset);
 
        BUG_ON(!PageLocked(page));
 
        if (PagePrivate(page)) {
+#ifdef AFS_CACHING_SUPPORT
+               struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
+               cachefs_uncache_page(vnode->cache,page);
+#endif
+
                /* We release buffers only if the entire page is being
                 * invalidated.
                 * The get_block cached value has been unconditionally
                 * invalidated, so real IO is not possible anymore.
                 */
-               if (offset == 0 && !PageWriteback(page))
-                       page->mapping->a_ops->releasepage(page, 0);
-       }
+               if (offset == 0) {
+                       BUG_ON(!PageLocked(page));
 
-       _leave("");
+                       ret = 0;
+                       if (!PageWriteback(page))
+                               ret = page->mapping->a_ops->releasepage(page,
+                                                                       0);
+               }
+       }
 
+       _leave(" = %d", ret);
+       return ret;
 } /* end afs_file_invalidatepage() */
 
 /*****************************************************************************/
@@ -326,30 +251,23 @@ static void afs_file_invalidatepage(struct page *page, unsigned long offset)
  */
 static int afs_file_releasepage(struct page *page, gfp_t gfp_flags)
 {
+       struct cachefs_page *pageio;
+
        _enter("{%lu},%x", page->index, gfp_flags);
 
-#ifdef CONFIG_AFS_FSCACHE
-       wait_on_page_fs_misc(page);
-       fscache_uncache_page(AFS_FS_I(page->mapping->host)->cache, page);
-       ClearPagePrivate(page);
+       if (PagePrivate(page)) {
+#ifdef AFS_CACHING_SUPPORT
+               struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
+               cachefs_uncache_page(vnode->cache, page);
 #endif
 
-       /* indicate that the page can be released */
-       _leave(" = 1");
-       return 1;
+               pageio = (struct cachefs_page *) page_private(page);
+               set_page_private(page, 0);
+               ClearPagePrivate(page);
 
-} /* end afs_file_releasepage() */
+               kfree(pageio);
+       }
 
-/*****************************************************************************/
-/*
- * wait for the disc cache to finish writing before permitting modification of
- * our page in the page cache
- */
-#ifdef CONFIG_AFS_FSCACHE
-static int afs_file_page_mkwrite(struct vm_area_struct *vma, struct page *page)
-{
-       wait_on_page_fs_misc(page);
+       _leave(" = 0");
        return 0;
-
-} /* end afs_file_page_mkwrite() */
-#endif
+} /* end afs_file_releasepage() */