afs: Set up the iov_iter before calling afs_extract_data()
[linux-2.6-microblaze.git] / fs / afs / write.c
index c9195fc..cb24f84 100644 (file)
@@ -22,12 +22,23 @@ int afs_set_page_dirty(struct page *page)
        return __set_page_dirty_nobuffers(page);
 }
 
+/*
+ * Handle completion of a read operation to fill a page.
+ */
+static void afs_fill_hole(struct afs_read *req)
+{
+       if (iov_iter_count(req->iter) > 0)
+               /* The read was short - clear the excess buffer. */
+               iov_iter_zero(iov_iter_count(req->iter), req->iter);
+}
+
 /*
  * partly or wholly fill a page that's under preparation for writing
  */
-static int afs_fill_page(struct afs_vnode *vnode, struct key *key,
+static int afs_fill_page(struct file *file,
                         loff_t pos, unsigned int len, struct page *page)
 {
+       struct afs_vnode *vnode = AFS_FS_I(file_inode(file));
        struct afs_read *req;
        size_t p;
        void *data;
@@ -44,19 +55,21 @@ static int afs_fill_page(struct afs_vnode *vnode, struct key *key,
                return 0;
        }
 
-       req = kzalloc(struct_size(req, array, 1), GFP_KERNEL);
+       req = kzalloc(sizeof(struct afs_read), GFP_KERNEL);
        if (!req)
                return -ENOMEM;
 
        refcount_set(&req->usage, 1);
-       req->pos = pos;
-       req->len = len;
-       req->nr_pages = 1;
-       req->pages = req->array;
-       req->pages[0] = page;
-       get_page(page);
-
-       ret = afs_fetch_data(vnode, key, req);
+       req->vnode      = vnode;
+       req->done       = afs_fill_hole;
+       req->key        = key_get(afs_file_key(file));
+       req->pos        = pos;
+       req->len        = len;
+       req->nr_pages   = 1;
+       req->iter       = &req->def_iter;
+       iov_iter_xarray(&req->def_iter, READ, &file->f_mapping->i_pages, pos, len);
+
+       ret = afs_fetch_data(vnode, req);
        afs_put_read(req);
        if (ret < 0) {
                if (ret == -ENOENT) {
@@ -80,7 +93,6 @@ int afs_write_begin(struct file *file, struct address_space *mapping,
 {
        struct afs_vnode *vnode = AFS_FS_I(file_inode(file));
        struct page *page;
-       struct key *key = afs_file_key(file);
        unsigned long priv;
        unsigned f, from = pos & (PAGE_SIZE - 1);
        unsigned t, to = from + len;
@@ -95,7 +107,7 @@ int afs_write_begin(struct file *file, struct address_space *mapping,
                return -ENOMEM;
 
        if (!PageUptodate(page) && len != PAGE_SIZE) {
-               ret = afs_fill_page(vnode, key, pos & PAGE_MASK, PAGE_SIZE, page);
+               ret = afs_fill_page(file, pos & PAGE_MASK, PAGE_SIZE, page);
                if (ret < 0) {
                        unlock_page(page);
                        put_page(page);
@@ -112,15 +124,14 @@ try_again:
        t = f = 0;
        if (PagePrivate(page)) {
                priv = page_private(page);
-               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);
                ASSERTCMP(f, <=, t);
        }
 
        if (f != t) {
                if (PageWriteback(page)) {
-                       trace_afs_page_dirty(vnode, tracepoint_string("alrdy"),
-                                            page->index, priv);
+                       trace_afs_page_dirty(vnode, tracepoint_string("alrdy"), page);
                        goto flush_conflicting_write;
                }
                /* If the file is being filled locally, allow inter-write
@@ -164,7 +175,6 @@ int afs_write_end(struct file *file, struct address_space *mapping,
                  struct page *page, void *fsdata)
 {
        struct afs_vnode *vnode = AFS_FS_I(file_inode(file));
-       struct key *key = afs_file_key(file);
        unsigned long priv;
        unsigned int f, from = pos & (PAGE_SIZE - 1);
        unsigned int t, to = from + copied;
@@ -194,7 +204,7 @@ int afs_write_end(struct file *file, struct address_space *mapping,
                         * unmarshalling routine will take care of clearing any
                         * bits that are beyond the EOF.
                         */
-                       ret = afs_fill_page(vnode, key, pos + copied,
+                       ret = afs_fill_page(file, pos + copied,
                                            len - copied, page);
                        if (ret < 0)
                                goto out;
@@ -204,21 +214,19 @@ int afs_write_end(struct file *file, struct address_space *mapping,
 
        if (PagePrivate(page)) {
                priv = page_private(page);
-               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 (from < f)
                        f = from;
                if (to > t)
                        t = to;
-               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("dirty+"),
-                                    page->index, priv);
+               trace_afs_page_dirty(vnode, tracepoint_string("dirty+"), page);
        } else {
-               priv = afs_page_dirty(from, to);
+               priv = afs_page_dirty(page, from, to);
                attach_page_private(page, (void *)priv);
-               trace_afs_page_dirty(vnode, tracepoint_string("dirty"),
-                                    page->index, priv);
+               trace_afs_page_dirty(vnode, tracepoint_string("dirty"), page);
        }
 
        set_page_dirty(page);
@@ -321,7 +329,6 @@ static void afs_pages_written_back(struct afs_vnode *vnode,
                                   pgoff_t first, pgoff_t last)
 {
        struct pagevec pv;
-       unsigned long priv;
        unsigned count, loop;
 
        _enter("{%llx:%llu},{%lx-%lx}",
@@ -340,9 +347,9 @@ static void afs_pages_written_back(struct afs_vnode *vnode,
                ASSERTCMP(pv.nr, ==, count);
 
                for (loop = 0; loop < count; loop++) {
-                       priv = (unsigned long)detach_page_private(pv.pages[loop]);
+                       detach_page_private(pv.pages[loop]);
                        trace_afs_page_dirty(vnode, tracepoint_string("clear"),
-                                            pv.pages[loop]->index, priv);
+                                            pv.pages[loop]);
                        end_page_writeback(pv.pages[loop]);
                }
                first += count;
@@ -516,15 +523,13 @@ static int afs_write_back_from_locked_page(struct address_space *mapping,
         */
        start = primary_page->index;
        priv = page_private(primary_page);
-       offset = afs_page_dirty_from(priv);
-       to = afs_page_dirty_to(priv);
-       trace_afs_page_dirty(vnode, tracepoint_string("store"),
-                            primary_page->index, priv);
+       offset = afs_page_dirty_from(primary_page, priv);
+       to = afs_page_dirty_to(primary_page, priv);
+       trace_afs_page_dirty(vnode, tracepoint_string("store"), primary_page);
 
        WARN_ON(offset == to);
        if (offset == to)
-               trace_afs_page_dirty(vnode, tracepoint_string("WARN"),
-                                    primary_page->index, priv);
+               trace_afs_page_dirty(vnode, tracepoint_string("WARN"), primary_page);
 
        if (start >= final_page ||
            (to < PAGE_SIZE && !test_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags)))
@@ -562,8 +567,8 @@ static int afs_write_back_from_locked_page(struct address_space *mapping,
                        }
 
                        priv = page_private(page);
-                       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 (f != 0 &&
                            !test_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags)) {
                                unlock_page(page);
@@ -571,8 +576,7 @@ static int afs_write_back_from_locked_page(struct address_space *mapping,
                        }
                        to = t;
 
-                       trace_afs_page_dirty(vnode, tracepoint_string("store+"),
-                                            page->index, priv);
+                       trace_afs_page_dirty(vnode, tracepoint_string("store+"), page);
 
                        if (!clear_page_dirty_for_io(page))
                                BUG();
@@ -847,12 +851,8 @@ vm_fault_t afs_page_mkwrite(struct vm_fault *vmf)
        /* Wait for the page to be written to the cache before we allow it to
         * be modified.  We then assume the entire page will need writing back.
         */
-#ifdef CONFIG_AFS_FSCACHE
-       fscache_wait_on_page_write(vnode->cache, vmf->page);
-#endif
 
-       if (PageWriteback(vmf->page) &&
-           wait_on_page_bit_killable(vmf->page, PG_writeback) < 0)
+       if (wait_on_page_writeback_killable(vmf->page))
                return VM_FAULT_RETRY;
 
        if (lock_page_killable(vmf->page) < 0)
@@ -864,14 +864,13 @@ vm_fault_t afs_page_mkwrite(struct vm_fault *vmf)
         */
        wait_on_page_writeback(vmf->page);
 
-       priv = afs_page_dirty(0, PAGE_SIZE);
+       priv = afs_page_dirty(vmf->page, 0, PAGE_SIZE);
        priv = afs_page_dirty_mmapped(priv);
-       trace_afs_page_dirty(vnode, tracepoint_string("mkwrite"),
-                            vmf->page->index, priv);
        if (PagePrivate(vmf->page))
                set_page_private(vmf->page, priv);
        else
                attach_page_private(vmf->page, (void *)priv);
+       trace_afs_page_dirty(vnode, tracepoint_string("mkwrite"), vmf->page);
        file_update_time(file);
 
        sb_end_pagefault(inode->i_sb);
@@ -924,24 +923,15 @@ int afs_launder_page(struct page *page)
                f = 0;
                t = PAGE_SIZE;
                if (PagePrivate(page)) {
-                       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);
                }
 
-               trace_afs_page_dirty(vnode, tracepoint_string("launder"),
-                                    page->index, priv);
+               trace_afs_page_dirty(vnode, tracepoint_string("launder"), page);
                ret = afs_store_data(mapping, page->index, page->index, t, f, true);
        }
 
-       priv = (unsigned long)detach_page_private(page);
-       trace_afs_page_dirty(vnode, tracepoint_string("laundered"),
-                            page->index, priv);
-
-#ifdef CONFIG_AFS_FSCACHE
-       if (PageFsCache(page)) {
-               fscache_wait_on_page_write(vnode->cache, page);
-               fscache_uncache_page(vnode->cache, page);
-       }
-#endif
+       detach_page_private(page);
+       trace_afs_page_dirty(vnode, tracepoint_string("laundered"), page);
        return ret;
 }