Merge tag 'mips_5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux
[linux-2.6-microblaze.git] / fs / afs / file.c
index 960b642..db035ae 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/gfp.h>
 #include <linux/task_io_accounting_ops.h>
 #include <linux/mm.h>
+#include <linux/netfs.h>
 #include "internal.h"
 
 static int afs_file_mmap(struct file *file, struct vm_area_struct *vma);
@@ -22,8 +23,7 @@ static void afs_invalidatepage(struct page *page, unsigned int offset,
                               unsigned int length);
 static int afs_releasepage(struct page *page, gfp_t gfp_flags);
 
-static int afs_readpages(struct file *filp, struct address_space *mapping,
-                        struct list_head *pages, unsigned nr_pages);
+static void afs_readahead(struct readahead_control *ractl);
 
 const struct file_operations afs_file_operations = {
        .open           = afs_open,
@@ -47,7 +47,7 @@ const struct inode_operations afs_file_inode_operations = {
 
 const struct address_space_operations afs_fs_aops = {
        .readpage       = afs_readpage,
-       .readpages      = afs_readpages,
+       .readahead      = afs_readahead,
        .set_page_dirty = afs_set_page_dirty,
        .launder_page   = afs_launder_page,
        .releasepage    = afs_releasepage,
@@ -183,42 +183,51 @@ int afs_release(struct inode *inode, struct file *file)
        return ret;
 }
 
+/*
+ * Allocate a new read record.
+ */
+struct afs_read *afs_alloc_read(gfp_t gfp)
+{
+       struct afs_read *req;
+
+       req = kzalloc(sizeof(struct afs_read), gfp);
+       if (req)
+               refcount_set(&req->usage, 1);
+
+       return req;
+}
+
 /*
  * Dispose of a ref to a read record.
  */
 void afs_put_read(struct afs_read *req)
 {
-       int i;
-
        if (refcount_dec_and_test(&req->usage)) {
-               if (req->pages) {
-                       for (i = 0; i < req->nr_pages; i++)
-                               if (req->pages[i])
-                                       put_page(req->pages[i]);
-                       if (req->pages != req->array)
-                               kfree(req->pages);
-               }
+               if (req->cleanup)
+                       req->cleanup(req);
+               key_put(req->key);
                kfree(req);
        }
 }
 
-#ifdef CONFIG_AFS_FSCACHE
-/*
- * deal with notification that a page was read from the cache
- */
-static void afs_file_readpage_read_complete(struct page *page,
-                                           void *data,
-                                           int error)
+static void afs_fetch_data_notify(struct afs_operation *op)
 {
-       _enter("%p,%p,%d", page, data, error);
-
-       /* if the read completes with an error, we just unlock the page and let
-        * the VM reissue the readpage */
-       if (!error)
-               SetPageUptodate(page);
-       unlock_page(page);
+       struct afs_read *req = op->fetch.req;
+       struct netfs_read_subrequest *subreq = req->subreq;
+       int error = op->error;
+
+       if (error == -ECONNABORTED)
+               error = afs_abort_to_error(op->ac.abort_code);
+       req->error = error;
+
+       if (subreq) {
+               __set_bit(NETFS_SREQ_CLEAR_TAIL, &subreq->flags);
+               netfs_subreq_terminated(subreq, error ?: req->actual_len, false);
+               req->subreq = NULL;
+       } else if (req->done) {
+               req->done(req);
+       }
 }
-#endif
 
 static void afs_fetch_data_success(struct afs_operation *op)
 {
@@ -228,10 +237,12 @@ static void afs_fetch_data_success(struct afs_operation *op)
        afs_vnode_commit_status(op, &op->file[0]);
        afs_stat_v(vnode, n_fetches);
        atomic_long_add(op->fetch.req->actual_len, &op->net->n_fetch_bytes);
+       afs_fetch_data_notify(op);
 }
 
 static void afs_fetch_data_put(struct afs_operation *op)
 {
+       op->fetch.req->error = op->error;
        afs_put_read(op->fetch.req);
 }
 
@@ -240,13 +251,14 @@ static const struct afs_operation_ops afs_fetch_data_operation = {
        .issue_yfs_rpc  = yfs_fs_fetch_data,
        .success        = afs_fetch_data_success,
        .aborted        = afs_check_for_remote_deletion,
+       .failed         = afs_fetch_data_notify,
        .put            = afs_fetch_data_put,
 };
 
 /*
  * Fetch file data from the volume.
  */
-int afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *req)
+int afs_fetch_data(struct afs_vnode *vnode, struct afs_read *req)
 {
        struct afs_operation *op;
 
@@ -255,11 +267,14 @@ int afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *re
               vnode->fid.vid,
               vnode->fid.vnode,
               vnode->fid.unique,
-              key_serial(key));
+              key_serial(req->key));
 
-       op = afs_alloc_operation(key, vnode->volume);
-       if (IS_ERR(op))
+       op = afs_alloc_operation(req->key, vnode->volume);
+       if (IS_ERR(op)) {
+               if (req->subreq)
+                       netfs_subreq_terminated(req->subreq, PTR_ERR(op), false);
                return PTR_ERR(op);
+       }
 
        afs_op_set_vnode(op, 0, vnode);
 
@@ -268,336 +283,103 @@ int afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *re
        return afs_do_sync_operation(op);
 }
 
-/*
- * read page from file, directory or symlink, given a key to use
- */
-int afs_page_filler(void *data, struct page *page)
+static void afs_req_issue_op(struct netfs_read_subrequest *subreq)
 {
-       struct inode *inode = page->mapping->host;
-       struct afs_vnode *vnode = AFS_FS_I(inode);
-       struct afs_read *req;
-       struct key *key = data;
-       int ret;
-
-       _enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index);
+       struct afs_vnode *vnode = AFS_FS_I(subreq->rreq->inode);
+       struct afs_read *fsreq;
 
-       BUG_ON(!PageLocked(page));
+       fsreq = afs_alloc_read(GFP_NOFS);
+       if (!fsreq)
+               return netfs_subreq_terminated(subreq, -ENOMEM, false);
 
-       ret = -ESTALE;
-       if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
-               goto error;
+       fsreq->subreq   = subreq;
+       fsreq->pos      = subreq->start + subreq->transferred;
+       fsreq->len      = subreq->len   - subreq->transferred;
+       fsreq->key      = subreq->rreq->netfs_priv;
+       fsreq->vnode    = vnode;
+       fsreq->iter     = &fsreq->def_iter;
 
-       /* is it cached? */
-#ifdef CONFIG_AFS_FSCACHE
-       ret = fscache_read_or_alloc_page(vnode->cache,
-                                        page,
-                                        afs_file_readpage_read_complete,
-                                        NULL,
-                                        GFP_KERNEL);
-#else
-       ret = -ENOBUFS;
-#endif
-       switch (ret) {
-               /* 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 */
-       case -ENOBUFS:
-               _debug("cache said ENOBUFS");
-
-               fallthrough;
-       default:
-       go_on:
-               req = kzalloc(struct_size(req, array, 1), GFP_KERNEL);
-               if (!req)
-                       goto enomem;
-
-               /* We request a full page.  If the page is a partial one at the
-                * end of the file, the server will return a short read and the
-                * unmarshalling code will clear the unfilled space.
-                */
-               refcount_set(&req->usage, 1);
-               req->pos = (loff_t)page->index << PAGE_SHIFT;
-               req->len = PAGE_SIZE;
-               req->nr_pages = 1;
-               req->pages = req->array;
-               req->pages[0] = page;
-               get_page(page);
-
-               /* read the contents of the file from the server into the
-                * page */
-               ret = afs_fetch_data(vnode, key, req);
-               afs_put_read(req);
-
-               if (ret < 0) {
-                       if (ret == -ENOENT) {
-                               _debug("got NOENT from server"
-                                      " - marking file deleted and stale");
-                               set_bit(AFS_VNODE_DELETED, &vnode->flags);
-                               ret = -ESTALE;
-                       }
+       iov_iter_xarray(&fsreq->def_iter, READ,
+                       &fsreq->vnode->vfs_inode.i_mapping->i_pages,
+                       fsreq->pos, fsreq->len);
 
-#ifdef CONFIG_AFS_FSCACHE
-                       fscache_uncache_page(vnode->cache, page);
-#endif
-                       BUG_ON(PageFsCache(page));
-
-                       if (ret == -EINTR ||
-                           ret == -ENOMEM ||
-                           ret == -ERESTARTSYS ||
-                           ret == -EAGAIN)
-                               goto error;
-                       goto io_error;
-               }
+       afs_fetch_data(fsreq->vnode, fsreq);
+}
 
-               SetPageUptodate(page);
+static int afs_symlink_readpage(struct page *page)
+{
+       struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
+       struct afs_read *fsreq;
+       int ret;
 
-               /* send the page to the cache */
-#ifdef CONFIG_AFS_FSCACHE
-               if (PageFsCache(page) &&
-                   fscache_write_page(vnode->cache, page, vnode->status.size,
-                                      GFP_KERNEL) != 0) {
-                       fscache_uncache_page(vnode->cache, page);
-                       BUG_ON(PageFsCache(page));
-               }
-#endif
-               unlock_page(page);
-       }
+       fsreq = afs_alloc_read(GFP_NOFS);
+       if (!fsreq)
+               return -ENOMEM;
 
-       _leave(" = 0");
-       return 0;
+       fsreq->pos      = page->index * PAGE_SIZE;
+       fsreq->len      = PAGE_SIZE;
+       fsreq->vnode    = vnode;
+       fsreq->iter     = &fsreq->def_iter;
+       iov_iter_xarray(&fsreq->def_iter, READ, &page->mapping->i_pages,
+                       fsreq->pos, fsreq->len);
 
-io_error:
-       SetPageError(page);
-       goto error;
-enomem:
-       ret = -ENOMEM;
-error:
-       unlock_page(page);
-       _leave(" = %d", ret);
+       ret = afs_fetch_data(fsreq->vnode, fsreq);
+       page_endio(page, false, ret);
        return ret;
 }
 
-/*
- * read page from file, directory or symlink, given a file to nominate the key
- * to be used
- */
-static int afs_readpage(struct file *file, struct page *page)
+static void afs_init_rreq(struct netfs_read_request *rreq, struct file *file)
 {
-       struct key *key;
-       int ret;
-
-       if (file) {
-               key = afs_file_key(file);
-               ASSERT(key != NULL);
-               ret = afs_page_filler(key, page);
-       } else {
-               struct inode *inode = page->mapping->host;
-               key = afs_request_key(AFS_FS_S(inode->i_sb)->cell);
-               if (IS_ERR(key)) {
-                       ret = PTR_ERR(key);
-               } else {
-                       ret = afs_page_filler(key, page);
-                       key_put(key);
-               }
-       }
-       return ret;
+       rreq->netfs_priv = key_get(afs_file_key(file));
 }
 
-/*
- * Make pages available as they're filled.
- */
-static void afs_readpages_page_done(struct afs_read *req)
+static bool afs_is_cache_enabled(struct inode *inode)
 {
-#ifdef CONFIG_AFS_FSCACHE
-       struct afs_vnode *vnode = req->vnode;
-#endif
-       struct page *page = req->pages[req->index];
+       struct fscache_cookie *cookie = afs_vnode_cache(AFS_FS_I(inode));
 
-       req->pages[req->index] = NULL;
-       SetPageUptodate(page);
-
-       /* send the page to the cache */
-#ifdef CONFIG_AFS_FSCACHE
-       if (PageFsCache(page) &&
-           fscache_write_page(vnode->cache, page, vnode->status.size,
-                              GFP_KERNEL) != 0) {
-               fscache_uncache_page(vnode->cache, page);
-               BUG_ON(PageFsCache(page));
-       }
-#endif
-       unlock_page(page);
-       put_page(page);
+       return fscache_cookie_enabled(cookie) && !hlist_empty(&cookie->backing_objects);
 }
 
-/*
- * Read a contiguous set of pages.
- */
-static int afs_readpages_one(struct file *file, struct address_space *mapping,
-                            struct list_head *pages)
+static int afs_begin_cache_operation(struct netfs_read_request *rreq)
 {
-       struct afs_vnode *vnode = AFS_FS_I(mapping->host);
-       struct afs_read *req;
-       struct list_head *p;
-       struct page *first, *page;
-       struct key *key = afs_file_key(file);
-       pgoff_t index;
-       int ret, n, i;
-
-       /* Count the number of contiguous pages at the front of the list.  Note
-        * that the list goes prev-wards rather than next-wards.
-        */
-       first = lru_to_page(pages);
-       index = first->index + 1;
-       n = 1;
-       for (p = first->lru.prev; p != pages; p = p->prev) {
-               page = list_entry(p, struct page, lru);
-               if (page->index != index)
-                       break;
-               index++;
-               n++;
-       }
-
-       req = kzalloc(struct_size(req, array, n), GFP_NOFS);
-       if (!req)
-               return -ENOMEM;
-
-       refcount_set(&req->usage, 1);
-       req->vnode = vnode;
-       req->page_done = afs_readpages_page_done;
-       req->pos = first->index;
-       req->pos <<= PAGE_SHIFT;
-       req->pages = req->array;
-
-       /* Transfer the pages to the request.  We add them in until one fails
-        * to add to the LRU and then we stop (as that'll make a hole in the
-        * contiguous run.
-        *
-        * Note that it's possible for the file size to change whilst we're
-        * doing this, but we rely on the server returning less than we asked
-        * for if the file shrank.  We also rely on this to deal with a partial
-        * page at the end of the file.
-        */
-       do {
-               page = lru_to_page(pages);
-               list_del(&page->lru);
-               index = page->index;
-               if (add_to_page_cache_lru(page, mapping, index,
-                                         readahead_gfp_mask(mapping))) {
-#ifdef CONFIG_AFS_FSCACHE
-                       fscache_uncache_page(vnode->cache, page);
-#endif
-                       put_page(page);
-                       break;
-               }
-
-               req->pages[req->nr_pages++] = page;
-               req->len += PAGE_SIZE;
-       } while (req->nr_pages < n);
+       struct afs_vnode *vnode = AFS_FS_I(rreq->inode);
 
-       if (req->nr_pages == 0) {
-               kfree(req);
-               return 0;
-       }
-
-       ret = afs_fetch_data(vnode, key, req);
-       if (ret < 0)
-               goto error;
-
-       task_io_account_read(PAGE_SIZE * req->nr_pages);
-       afs_put_read(req);
-       return 0;
-
-error:
-       if (ret == -ENOENT) {
-               _debug("got NOENT from server"
-                      " - marking file deleted and stale");
-               set_bit(AFS_VNODE_DELETED, &vnode->flags);
-               ret = -ESTALE;
-       }
-
-       for (i = 0; i < req->nr_pages; i++) {
-               page = req->pages[i];
-               if (page) {
-#ifdef CONFIG_AFS_FSCACHE
-                       fscache_uncache_page(vnode->cache, page);
-#endif
-                       SetPageError(page);
-                       unlock_page(page);
-               }
-       }
-
-       afs_put_read(req);
-       return ret;
+       return fscache_begin_read_operation(rreq, afs_vnode_cache(vnode));
 }
 
-/*
- * read a set of pages
- */
-static int afs_readpages(struct file *file, struct address_space *mapping,
-                        struct list_head *pages, unsigned nr_pages)
+static int afs_check_write_begin(struct file *file, loff_t pos, unsigned len,
+                                struct page *page, void **_fsdata)
 {
-       struct key *key = afs_file_key(file);
-       struct afs_vnode *vnode;
-       int ret = 0;
-
-       _enter("{%d},{%lu},,%d",
-              key_serial(key), mapping->host->i_ino, nr_pages);
+       struct afs_vnode *vnode = AFS_FS_I(file_inode(file));
 
-       ASSERT(key != NULL);
+       return test_bit(AFS_VNODE_DELETED, &vnode->flags) ? -ESTALE : 0;
+}
 
-       vnode = AFS_FS_I(mapping->host);
-       if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
-               _leave(" = -ESTALE");
-               return -ESTALE;
-       }
+static void afs_priv_cleanup(struct address_space *mapping, void *netfs_priv)
+{
+       key_put(netfs_priv);
+}
 
-       /* attempt to read as many of the pages as possible */
-#ifdef CONFIG_AFS_FSCACHE
-       ret = fscache_read_or_alloc_pages(vnode->cache,
-                                         mapping,
-                                         pages,
-                                         &nr_pages,
-                                         afs_file_readpage_read_complete,
-                                         NULL,
-                                         mapping_gfp_mask(mapping));
-#else
-       ret = -ENOBUFS;
-#endif
+const struct netfs_read_request_ops afs_req_ops = {
+       .init_rreq              = afs_init_rreq,
+       .is_cache_enabled       = afs_is_cache_enabled,
+       .begin_cache_operation  = afs_begin_cache_operation,
+       .check_write_begin      = afs_check_write_begin,
+       .issue_op               = afs_req_issue_op,
+       .cleanup                = afs_priv_cleanup,
+};
 
-       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;
-       }
+static int afs_readpage(struct file *file, struct page *page)
+{
+       if (!file)
+               return afs_symlink_readpage(page);
 
-       while (!list_empty(pages)) {
-               ret = afs_readpages_one(file, mapping, pages);
-               if (ret < 0)
-                       break;
-       }
+       return netfs_readpage(file, page, &afs_req_ops, NULL);
+}
 
-       _leave(" = %d [netting]", ret);
-       return ret;
+static void afs_readahead(struct readahead_control *ractl)
+{
+       netfs_readahead(ractl, &afs_req_ops, NULL);
 }
 
 /*
@@ -625,8 +407,8 @@ static void afs_invalidate_dirty(struct page *page, unsigned int offset,
                return;
 
        /* We may need to shorten the dirty region */
-       f = afs_page_dirty_from(priv);
-       t = afs_page_dirty_to(priv);
+       f = afs_page_dirty_from(page, priv);
+       t = afs_page_dirty_to(page, priv);
 
        if (t <= offset || f >= end)
                return; /* Doesn't overlap */
@@ -644,17 +426,17 @@ static void afs_invalidate_dirty(struct page *page, unsigned int offset,
        if (f == t)
                goto undirty;
 
-       priv = afs_page_dirty(f, t);
+       priv = afs_page_dirty(page, f, t);
        set_page_private(page, priv);
-       trace_afs_page_dirty(vnode, tracepoint_string("trunc"), page->index, priv);
+       trace_afs_page_dirty(vnode, tracepoint_string("trunc"), page);
        return;
 
 undirty:
-       trace_afs_page_dirty(vnode, tracepoint_string("undirty"), page->index, priv);
+       trace_afs_page_dirty(vnode, tracepoint_string("undirty"), page);
        clear_page_dirty_for_io(page);
 full_invalidate:
-       priv = (unsigned long)detach_page_private(page);
-       trace_afs_page_dirty(vnode, tracepoint_string("inval"), page->index, priv);
+       trace_afs_page_dirty(vnode, tracepoint_string("inval"), page);
+       detach_page_private(page);
 }
 
 /*
@@ -669,20 +451,10 @@ static void afs_invalidatepage(struct page *page, unsigned int offset,
 
        BUG_ON(!PageLocked(page));
 
-#ifdef CONFIG_AFS_FSCACHE
-       /* we clean up only if the entire page is being invalidated */
-       if (offset == 0 && length == PAGE_SIZE) {
-               if (PageFsCache(page)) {
-                       struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
-                       fscache_wait_on_page_write(vnode->cache, page);
-                       fscache_uncache_page(vnode->cache, page);
-               }
-       }
-#endif
-
        if (PagePrivate(page))
                afs_invalidate_dirty(page, offset, length);
 
+       wait_on_page_fscache(page);
        _leave("");
 }
 
@@ -693,7 +465,6 @@ static void afs_invalidatepage(struct page *page, unsigned int offset,
 static int afs_releasepage(struct page *page, gfp_t gfp_flags)
 {
        struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
-       unsigned long priv;
 
        _enter("{{%llx:%llu}[%lu],%lx},%x",
               vnode->fid.vid, vnode->fid.vnode, page->index, page->flags,
@@ -702,16 +473,16 @@ static int afs_releasepage(struct page *page, gfp_t gfp_flags)
        /* deny if page is being written to the cache and the caller hasn't
         * elected to wait */
 #ifdef CONFIG_AFS_FSCACHE
-       if (!fscache_maybe_release_page(vnode->cache, page, gfp_flags)) {
-               _leave(" = F [cache busy]");
-               return 0;
+       if (PageFsCache(page)) {
+               if (!(gfp_flags & __GFP_DIRECT_RECLAIM) || !(gfp_flags & __GFP_FS))
+                       return false;
+               wait_on_page_fscache(page);
        }
 #endif
 
        if (PagePrivate(page)) {
-               priv = (unsigned long)detach_page_private(page);
-               trace_afs_page_dirty(vnode, tracepoint_string("rel"),
-                                    page->index, priv);
+               trace_afs_page_dirty(vnode, tracepoint_string("rel"), page);
+               detach_page_private(page);
        }
 
        /* indicate that the page can be released */