131143d5dSDavid Howells /* handling of writes to regular files and writing back to the server 231143d5dSDavid Howells * 331143d5dSDavid Howells * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. 431143d5dSDavid Howells * Written by David Howells (dhowells@redhat.com) 531143d5dSDavid Howells * 631143d5dSDavid Howells * This program is free software; you can redistribute it and/or 731143d5dSDavid Howells * modify it under the terms of the GNU General Public License 831143d5dSDavid Howells * as published by the Free Software Foundation; either version 931143d5dSDavid Howells * 2 of the License, or (at your option) any later version. 1031143d5dSDavid Howells */ 1131143d5dSDavid Howells 1231143d5dSDavid Howells #include <linux/slab.h> 1331143d5dSDavid Howells #include <linux/fs.h> 1431143d5dSDavid Howells #include <linux/pagemap.h> 1531143d5dSDavid Howells #include <linux/writeback.h> 1631143d5dSDavid Howells #include <linux/pagevec.h> 1731143d5dSDavid Howells #include "internal.h" 1831143d5dSDavid Howells 1931143d5dSDavid Howells static int afs_write_back_from_locked_page(struct afs_writeback *wb, 2031143d5dSDavid Howells struct page *page); 2131143d5dSDavid Howells 2231143d5dSDavid Howells /* 2331143d5dSDavid Howells * mark a page as having been made dirty and thus needing writeback 2431143d5dSDavid Howells */ 2531143d5dSDavid Howells int afs_set_page_dirty(struct page *page) 2631143d5dSDavid Howells { 2731143d5dSDavid Howells _enter(""); 2831143d5dSDavid Howells return __set_page_dirty_nobuffers(page); 2931143d5dSDavid Howells } 3031143d5dSDavid Howells 3131143d5dSDavid Howells /* 3231143d5dSDavid Howells * unlink a writeback record because its usage has reached zero 3331143d5dSDavid Howells * - must be called with the wb->vnode->writeback_lock held 3431143d5dSDavid Howells */ 3531143d5dSDavid Howells static void afs_unlink_writeback(struct afs_writeback *wb) 3631143d5dSDavid Howells { 3731143d5dSDavid Howells struct afs_writeback *front; 3831143d5dSDavid Howells struct afs_vnode *vnode = wb->vnode; 3931143d5dSDavid Howells 4031143d5dSDavid Howells list_del_init(&wb->link); 4131143d5dSDavid Howells if (!list_empty(&vnode->writebacks)) { 4231143d5dSDavid Howells /* if an fsync rises to the front of the queue then wake it 4331143d5dSDavid Howells * up */ 4431143d5dSDavid Howells front = list_entry(vnode->writebacks.next, 4531143d5dSDavid Howells struct afs_writeback, link); 4631143d5dSDavid Howells if (front->state == AFS_WBACK_SYNCING) { 4731143d5dSDavid Howells _debug("wake up sync"); 4831143d5dSDavid Howells front->state = AFS_WBACK_COMPLETE; 4931143d5dSDavid Howells wake_up(&front->waitq); 5031143d5dSDavid Howells } 5131143d5dSDavid Howells } 5231143d5dSDavid Howells } 5331143d5dSDavid Howells 5431143d5dSDavid Howells /* 5531143d5dSDavid Howells * free a writeback record 5631143d5dSDavid Howells */ 5731143d5dSDavid Howells static void afs_free_writeback(struct afs_writeback *wb) 5831143d5dSDavid Howells { 5931143d5dSDavid Howells _enter(""); 6031143d5dSDavid Howells key_put(wb->key); 6131143d5dSDavid Howells kfree(wb); 6231143d5dSDavid Howells } 6331143d5dSDavid Howells 6431143d5dSDavid Howells /* 6531143d5dSDavid Howells * dispose of a reference to a writeback record 6631143d5dSDavid Howells */ 6731143d5dSDavid Howells void afs_put_writeback(struct afs_writeback *wb) 6831143d5dSDavid Howells { 6931143d5dSDavid Howells struct afs_vnode *vnode = wb->vnode; 7031143d5dSDavid Howells 7131143d5dSDavid Howells _enter("{%d}", wb->usage); 7231143d5dSDavid Howells 7331143d5dSDavid Howells spin_lock(&vnode->writeback_lock); 7431143d5dSDavid Howells if (--wb->usage == 0) 7531143d5dSDavid Howells afs_unlink_writeback(wb); 7631143d5dSDavid Howells else 7731143d5dSDavid Howells wb = NULL; 7831143d5dSDavid Howells spin_unlock(&vnode->writeback_lock); 7931143d5dSDavid Howells if (wb) 8031143d5dSDavid Howells afs_free_writeback(wb); 8131143d5dSDavid Howells } 8231143d5dSDavid Howells 8331143d5dSDavid Howells /* 8431143d5dSDavid Howells * partly or wholly fill a page that's under preparation for writing 8531143d5dSDavid Howells */ 8631143d5dSDavid Howells static int afs_fill_page(struct afs_vnode *vnode, struct key *key, 8731143d5dSDavid Howells unsigned start, unsigned len, struct page *page) 8831143d5dSDavid Howells { 8931143d5dSDavid Howells int ret; 9031143d5dSDavid Howells 9131143d5dSDavid Howells _enter(",,%u,%u", start, len); 9231143d5dSDavid Howells 9331143d5dSDavid Howells ASSERTCMP(start + len, <=, PAGE_SIZE); 9431143d5dSDavid Howells 9531143d5dSDavid Howells ret = afs_vnode_fetch_data(vnode, key, start, len, page); 9631143d5dSDavid Howells if (ret < 0) { 9731143d5dSDavid Howells if (ret == -ENOENT) { 9831143d5dSDavid Howells _debug("got NOENT from server" 9931143d5dSDavid Howells " - marking file deleted and stale"); 10031143d5dSDavid Howells set_bit(AFS_VNODE_DELETED, &vnode->flags); 10131143d5dSDavid Howells ret = -ESTALE; 10231143d5dSDavid Howells } 10331143d5dSDavid Howells } 10431143d5dSDavid Howells 10531143d5dSDavid Howells _leave(" = %d", ret); 10631143d5dSDavid Howells return ret; 10731143d5dSDavid Howells } 10831143d5dSDavid Howells 10931143d5dSDavid Howells /* 11031143d5dSDavid Howells * prepare a page for being written to 11131143d5dSDavid Howells */ 11231143d5dSDavid Howells static int afs_prepare_page(struct afs_vnode *vnode, struct page *page, 11331143d5dSDavid Howells struct key *key, unsigned offset, unsigned to) 11431143d5dSDavid Howells { 11531143d5dSDavid Howells unsigned eof, tail, start, stop, len; 11631143d5dSDavid Howells loff_t i_size, pos; 11731143d5dSDavid Howells void *p; 11831143d5dSDavid Howells int ret; 11931143d5dSDavid Howells 12031143d5dSDavid Howells _enter(""); 12131143d5dSDavid Howells 12231143d5dSDavid Howells if (offset == 0 && to == PAGE_SIZE) 12331143d5dSDavid Howells return 0; 12431143d5dSDavid Howells 125b9b1f8d5SDavid Howells p = kmap_atomic(page, KM_USER0); 12631143d5dSDavid Howells 12731143d5dSDavid Howells i_size = i_size_read(&vnode->vfs_inode); 12831143d5dSDavid Howells pos = (loff_t) page->index << PAGE_SHIFT; 12931143d5dSDavid Howells if (pos >= i_size) { 13031143d5dSDavid Howells /* partial write, page beyond EOF */ 13131143d5dSDavid Howells _debug("beyond"); 13231143d5dSDavid Howells if (offset > 0) 13331143d5dSDavid Howells memset(p, 0, offset); 13431143d5dSDavid Howells if (to < PAGE_SIZE) 13531143d5dSDavid Howells memset(p + to, 0, PAGE_SIZE - to); 136b9b1f8d5SDavid Howells kunmap_atomic(p, KM_USER0); 13731143d5dSDavid Howells return 0; 13831143d5dSDavid Howells } 13931143d5dSDavid Howells 14031143d5dSDavid Howells if (i_size - pos >= PAGE_SIZE) { 14131143d5dSDavid Howells /* partial write, page entirely before EOF */ 14231143d5dSDavid Howells _debug("before"); 14331143d5dSDavid Howells tail = eof = PAGE_SIZE; 14431143d5dSDavid Howells } else { 14531143d5dSDavid Howells /* partial write, page overlaps EOF */ 14631143d5dSDavid Howells eof = i_size - pos; 14731143d5dSDavid Howells _debug("overlap %u", eof); 14831143d5dSDavid Howells tail = max(eof, to); 14931143d5dSDavid Howells if (tail < PAGE_SIZE) 15031143d5dSDavid Howells memset(p + tail, 0, PAGE_SIZE - tail); 15131143d5dSDavid Howells if (offset > eof) 15231143d5dSDavid Howells memset(p + eof, 0, PAGE_SIZE - eof); 15331143d5dSDavid Howells } 15431143d5dSDavid Howells 155b9b1f8d5SDavid Howells kunmap_atomic(p, KM_USER0); 15631143d5dSDavid Howells 15731143d5dSDavid Howells ret = 0; 15831143d5dSDavid Howells if (offset > 0 || eof > to) { 15931143d5dSDavid Howells /* need to fill one or two bits that aren't going to be written 16031143d5dSDavid Howells * (cover both fillers in one read if there are two) */ 16131143d5dSDavid Howells start = (offset > 0) ? 0 : to; 16231143d5dSDavid Howells stop = (eof > to) ? eof : offset; 16331143d5dSDavid Howells len = stop - start; 16431143d5dSDavid Howells _debug("wr=%u-%u av=0-%u rd=%u@%u", 16531143d5dSDavid Howells offset, to, eof, start, len); 16631143d5dSDavid Howells ret = afs_fill_page(vnode, key, start, len, page); 16731143d5dSDavid Howells } 16831143d5dSDavid Howells 16931143d5dSDavid Howells _leave(" = %d", ret); 17031143d5dSDavid Howells return ret; 17131143d5dSDavid Howells } 17231143d5dSDavid Howells 17331143d5dSDavid Howells /* 17431143d5dSDavid Howells * prepare to perform part of a write to a page 17531143d5dSDavid Howells * - the caller holds the page locked, preventing it from being written out or 17631143d5dSDavid Howells * modified by anyone else 17731143d5dSDavid Howells */ 17831143d5dSDavid Howells int afs_prepare_write(struct file *file, struct page *page, 17931143d5dSDavid Howells unsigned offset, unsigned to) 18031143d5dSDavid Howells { 18131143d5dSDavid Howells struct afs_writeback *candidate, *wb; 18231143d5dSDavid Howells struct afs_vnode *vnode = AFS_FS_I(file->f_dentry->d_inode); 18331143d5dSDavid Howells struct key *key = file->private_data; 18431143d5dSDavid Howells pgoff_t index; 18531143d5dSDavid Howells int ret; 18631143d5dSDavid Howells 18731143d5dSDavid Howells _enter("{%x:%u},{%lx},%u,%u", 18831143d5dSDavid Howells vnode->fid.vid, vnode->fid.vnode, page->index, offset, to); 18931143d5dSDavid Howells 19031143d5dSDavid Howells candidate = kzalloc(sizeof(*candidate), GFP_KERNEL); 19131143d5dSDavid Howells if (!candidate) 19231143d5dSDavid Howells return -ENOMEM; 19331143d5dSDavid Howells candidate->vnode = vnode; 19431143d5dSDavid Howells candidate->first = candidate->last = page->index; 19531143d5dSDavid Howells candidate->offset_first = offset; 19631143d5dSDavid Howells candidate->to_last = to; 19731143d5dSDavid Howells candidate->usage = 1; 19831143d5dSDavid Howells candidate->state = AFS_WBACK_PENDING; 19931143d5dSDavid Howells init_waitqueue_head(&candidate->waitq); 20031143d5dSDavid Howells 20131143d5dSDavid Howells if (!PageUptodate(page)) { 20231143d5dSDavid Howells _debug("not up to date"); 20331143d5dSDavid Howells ret = afs_prepare_page(vnode, page, key, offset, to); 20431143d5dSDavid Howells if (ret < 0) { 20531143d5dSDavid Howells kfree(candidate); 20631143d5dSDavid Howells _leave(" = %d [prep]", ret); 20731143d5dSDavid Howells return ret; 20831143d5dSDavid Howells } 20931143d5dSDavid Howells SetPageUptodate(page); 21031143d5dSDavid Howells } 21131143d5dSDavid Howells 21231143d5dSDavid Howells try_again: 21331143d5dSDavid Howells index = page->index; 21431143d5dSDavid Howells spin_lock(&vnode->writeback_lock); 21531143d5dSDavid Howells 21631143d5dSDavid Howells /* see if this page is already pending a writeback under a suitable key 21731143d5dSDavid Howells * - if so we can just join onto that one */ 21831143d5dSDavid Howells wb = (struct afs_writeback *) page_private(page); 21931143d5dSDavid Howells if (wb) { 22031143d5dSDavid Howells if (wb->key == key && wb->state == AFS_WBACK_PENDING) 22131143d5dSDavid Howells goto subsume_in_current_wb; 22231143d5dSDavid Howells goto flush_conflicting_wb; 22331143d5dSDavid Howells } 22431143d5dSDavid Howells 22531143d5dSDavid Howells if (index > 0) { 22631143d5dSDavid Howells /* see if we can find an already pending writeback that we can 22731143d5dSDavid Howells * append this page to */ 22831143d5dSDavid Howells list_for_each_entry(wb, &vnode->writebacks, link) { 22931143d5dSDavid Howells if (wb->last == index - 1 && wb->key == key && 23031143d5dSDavid Howells wb->state == AFS_WBACK_PENDING) 23131143d5dSDavid Howells goto append_to_previous_wb; 23231143d5dSDavid Howells } 23331143d5dSDavid Howells } 23431143d5dSDavid Howells 23531143d5dSDavid Howells list_add_tail(&candidate->link, &vnode->writebacks); 23631143d5dSDavid Howells candidate->key = key_get(key); 23731143d5dSDavid Howells spin_unlock(&vnode->writeback_lock); 23831143d5dSDavid Howells SetPagePrivate(page); 23931143d5dSDavid Howells set_page_private(page, (unsigned long) candidate); 24031143d5dSDavid Howells _leave(" = 0 [new]"); 24131143d5dSDavid Howells return 0; 24231143d5dSDavid Howells 24331143d5dSDavid Howells subsume_in_current_wb: 24431143d5dSDavid Howells _debug("subsume"); 24531143d5dSDavid Howells ASSERTRANGE(wb->first, <=, index, <=, wb->last); 24631143d5dSDavid Howells if (index == wb->first && offset < wb->offset_first) 24731143d5dSDavid Howells wb->offset_first = offset; 24831143d5dSDavid Howells if (index == wb->last && to > wb->to_last) 24931143d5dSDavid Howells wb->to_last = to; 25031143d5dSDavid Howells spin_unlock(&vnode->writeback_lock); 25131143d5dSDavid Howells kfree(candidate); 25231143d5dSDavid Howells _leave(" = 0 [sub]"); 25331143d5dSDavid Howells return 0; 25431143d5dSDavid Howells 25531143d5dSDavid Howells append_to_previous_wb: 25631143d5dSDavid Howells _debug("append into %lx-%lx", wb->first, wb->last); 25731143d5dSDavid Howells wb->usage++; 25831143d5dSDavid Howells wb->last++; 25931143d5dSDavid Howells wb->to_last = to; 26031143d5dSDavid Howells spin_unlock(&vnode->writeback_lock); 26131143d5dSDavid Howells SetPagePrivate(page); 26231143d5dSDavid Howells set_page_private(page, (unsigned long) wb); 26331143d5dSDavid Howells kfree(candidate); 26431143d5dSDavid Howells _leave(" = 0 [app]"); 26531143d5dSDavid Howells return 0; 26631143d5dSDavid Howells 26731143d5dSDavid Howells /* the page is currently bound to another context, so if it's dirty we 26831143d5dSDavid Howells * need to flush it before we can use the new context */ 26931143d5dSDavid Howells flush_conflicting_wb: 27031143d5dSDavid Howells _debug("flush conflict"); 27131143d5dSDavid Howells if (wb->state == AFS_WBACK_PENDING) 27231143d5dSDavid Howells wb->state = AFS_WBACK_CONFLICTING; 27331143d5dSDavid Howells spin_unlock(&vnode->writeback_lock); 27431143d5dSDavid Howells if (PageDirty(page)) { 27531143d5dSDavid Howells ret = afs_write_back_from_locked_page(wb, page); 27631143d5dSDavid Howells if (ret < 0) { 27731143d5dSDavid Howells afs_put_writeback(candidate); 27831143d5dSDavid Howells _leave(" = %d", ret); 27931143d5dSDavid Howells return ret; 28031143d5dSDavid Howells } 28131143d5dSDavid Howells } 28231143d5dSDavid Howells 28331143d5dSDavid Howells /* the page holds a ref on the writeback record */ 28431143d5dSDavid Howells afs_put_writeback(wb); 28531143d5dSDavid Howells set_page_private(page, 0); 28631143d5dSDavid Howells ClearPagePrivate(page); 28731143d5dSDavid Howells goto try_again; 28831143d5dSDavid Howells } 28931143d5dSDavid Howells 29031143d5dSDavid Howells /* 29131143d5dSDavid Howells * finalise part of a write to a page 29231143d5dSDavid Howells */ 29331143d5dSDavid Howells int afs_commit_write(struct file *file, struct page *page, 29431143d5dSDavid Howells unsigned offset, unsigned to) 29531143d5dSDavid Howells { 29631143d5dSDavid Howells struct afs_vnode *vnode = AFS_FS_I(file->f_dentry->d_inode); 29731143d5dSDavid Howells loff_t i_size, maybe_i_size; 29831143d5dSDavid Howells 29931143d5dSDavid Howells _enter("{%x:%u},{%lx},%u,%u", 30031143d5dSDavid Howells vnode->fid.vid, vnode->fid.vnode, page->index, offset, to); 30131143d5dSDavid Howells 30231143d5dSDavid Howells maybe_i_size = (loff_t) page->index << PAGE_SHIFT; 30331143d5dSDavid Howells maybe_i_size += to; 30431143d5dSDavid Howells 30531143d5dSDavid Howells i_size = i_size_read(&vnode->vfs_inode); 30631143d5dSDavid Howells if (maybe_i_size > i_size) { 30731143d5dSDavid Howells spin_lock(&vnode->writeback_lock); 30831143d5dSDavid Howells i_size = i_size_read(&vnode->vfs_inode); 30931143d5dSDavid Howells if (maybe_i_size > i_size) 31031143d5dSDavid Howells i_size_write(&vnode->vfs_inode, maybe_i_size); 31131143d5dSDavid Howells spin_unlock(&vnode->writeback_lock); 31231143d5dSDavid Howells } 31331143d5dSDavid Howells 31431143d5dSDavid Howells set_page_dirty(page); 31531143d5dSDavid Howells 31631143d5dSDavid Howells if (PageDirty(page)) 31731143d5dSDavid Howells _debug("dirtied"); 31831143d5dSDavid Howells 31931143d5dSDavid Howells return 0; 32031143d5dSDavid Howells } 32131143d5dSDavid Howells 32231143d5dSDavid Howells /* 32331143d5dSDavid Howells * kill all the pages in the given range 32431143d5dSDavid Howells */ 32531143d5dSDavid Howells static void afs_kill_pages(struct afs_vnode *vnode, bool error, 32631143d5dSDavid Howells pgoff_t first, pgoff_t last) 32731143d5dSDavid Howells { 32831143d5dSDavid Howells struct pagevec pv; 32931143d5dSDavid Howells unsigned count, loop; 33031143d5dSDavid Howells 33131143d5dSDavid Howells _enter("{%x:%u},%lx-%lx", 33231143d5dSDavid Howells vnode->fid.vid, vnode->fid.vnode, first, last); 33331143d5dSDavid Howells 33431143d5dSDavid Howells pagevec_init(&pv, 0); 33531143d5dSDavid Howells 33631143d5dSDavid Howells do { 33731143d5dSDavid Howells _debug("kill %lx-%lx", first, last); 33831143d5dSDavid Howells 33931143d5dSDavid Howells count = last - first + 1; 34031143d5dSDavid Howells if (count > PAGEVEC_SIZE) 34131143d5dSDavid Howells count = PAGEVEC_SIZE; 34231143d5dSDavid Howells pv.nr = find_get_pages_contig(vnode->vfs_inode.i_mapping, 34331143d5dSDavid Howells first, count, pv.pages); 34431143d5dSDavid Howells ASSERTCMP(pv.nr, ==, count); 34531143d5dSDavid Howells 34631143d5dSDavid Howells for (loop = 0; loop < count; loop++) { 34731143d5dSDavid Howells ClearPageUptodate(pv.pages[loop]); 34831143d5dSDavid Howells if (error) 34931143d5dSDavid Howells SetPageError(pv.pages[loop]); 35031143d5dSDavid Howells end_page_writeback(pv.pages[loop]); 35131143d5dSDavid Howells } 35231143d5dSDavid Howells 35331143d5dSDavid Howells __pagevec_release(&pv); 35431143d5dSDavid Howells } while (first < last); 35531143d5dSDavid Howells 35631143d5dSDavid Howells _leave(""); 35731143d5dSDavid Howells } 35831143d5dSDavid Howells 35931143d5dSDavid Howells /* 36031143d5dSDavid Howells * synchronously write back the locked page and any subsequent non-locked dirty 36131143d5dSDavid Howells * pages also covered by the same writeback record 36231143d5dSDavid Howells */ 36331143d5dSDavid Howells static int afs_write_back_from_locked_page(struct afs_writeback *wb, 36431143d5dSDavid Howells struct page *primary_page) 36531143d5dSDavid Howells { 36631143d5dSDavid Howells struct page *pages[8], *page; 36731143d5dSDavid Howells unsigned long count; 36831143d5dSDavid Howells unsigned n, offset, to; 36931143d5dSDavid Howells pgoff_t start, first, last; 37031143d5dSDavid Howells int loop, ret; 37131143d5dSDavid Howells 37231143d5dSDavid Howells _enter(",%lx", primary_page->index); 37331143d5dSDavid Howells 37431143d5dSDavid Howells count = 1; 37531143d5dSDavid Howells if (!clear_page_dirty_for_io(primary_page)) 37631143d5dSDavid Howells BUG(); 37731143d5dSDavid Howells if (test_set_page_writeback(primary_page)) 37831143d5dSDavid Howells BUG(); 37931143d5dSDavid Howells 38031143d5dSDavid Howells /* find all consecutive lockable dirty pages, stopping when we find a 38131143d5dSDavid Howells * page that is not immediately lockable, is not dirty or is missing, 38231143d5dSDavid Howells * or we reach the end of the range */ 38331143d5dSDavid Howells start = primary_page->index; 38431143d5dSDavid Howells if (start >= wb->last) 38531143d5dSDavid Howells goto no_more; 38631143d5dSDavid Howells start++; 38731143d5dSDavid Howells do { 38831143d5dSDavid Howells _debug("more %lx [%lx]", start, count); 38931143d5dSDavid Howells n = wb->last - start + 1; 39031143d5dSDavid Howells if (n > ARRAY_SIZE(pages)) 39131143d5dSDavid Howells n = ARRAY_SIZE(pages); 39231143d5dSDavid Howells n = find_get_pages_contig(wb->vnode->vfs_inode.i_mapping, 39331143d5dSDavid Howells start, n, pages); 39431143d5dSDavid Howells _debug("fgpc %u", n); 39531143d5dSDavid Howells if (n == 0) 39631143d5dSDavid Howells goto no_more; 39731143d5dSDavid Howells if (pages[0]->index != start) { 39831143d5dSDavid Howells for (n--; n >= 0; n--) 39931143d5dSDavid Howells put_page(pages[n]); 40031143d5dSDavid Howells goto no_more; 40131143d5dSDavid Howells } 40231143d5dSDavid Howells 40331143d5dSDavid Howells for (loop = 0; loop < n; loop++) { 40431143d5dSDavid Howells page = pages[loop]; 40531143d5dSDavid Howells if (page->index > wb->last) 40631143d5dSDavid Howells break; 40731143d5dSDavid Howells if (TestSetPageLocked(page)) 40831143d5dSDavid Howells break; 40931143d5dSDavid Howells if (!PageDirty(page) || 41031143d5dSDavid Howells page_private(page) != (unsigned long) wb) { 41131143d5dSDavid Howells unlock_page(page); 41231143d5dSDavid Howells break; 41331143d5dSDavid Howells } 41431143d5dSDavid Howells if (!clear_page_dirty_for_io(page)) 41531143d5dSDavid Howells BUG(); 41631143d5dSDavid Howells if (test_set_page_writeback(page)) 41731143d5dSDavid Howells BUG(); 41831143d5dSDavid Howells unlock_page(page); 41931143d5dSDavid Howells put_page(page); 42031143d5dSDavid Howells } 42131143d5dSDavid Howells count += loop; 42231143d5dSDavid Howells if (loop < n) { 42331143d5dSDavid Howells for (; loop < n; loop++) 42431143d5dSDavid Howells put_page(pages[loop]); 42531143d5dSDavid Howells goto no_more; 42631143d5dSDavid Howells } 42731143d5dSDavid Howells 42831143d5dSDavid Howells start += loop; 42931143d5dSDavid Howells } while (start <= wb->last && count < 65536); 43031143d5dSDavid Howells 43131143d5dSDavid Howells no_more: 43231143d5dSDavid Howells /* we now have a contiguous set of dirty pages, each with writeback set 43331143d5dSDavid Howells * and the dirty mark cleared; the first page is locked and must remain 43431143d5dSDavid Howells * so, all the rest are unlocked */ 43531143d5dSDavid Howells first = primary_page->index; 43631143d5dSDavid Howells last = first + count - 1; 43731143d5dSDavid Howells 43831143d5dSDavid Howells offset = (first == wb->first) ? wb->offset_first : 0; 43931143d5dSDavid Howells to = (last == wb->last) ? wb->to_last : PAGE_SIZE; 44031143d5dSDavid Howells 44131143d5dSDavid Howells _debug("write back %lx[%u..] to %lx[..%u]", first, offset, last, to); 44231143d5dSDavid Howells 44331143d5dSDavid Howells ret = afs_vnode_store_data(wb, first, last, offset, to); 44431143d5dSDavid Howells if (ret < 0) { 44531143d5dSDavid Howells switch (ret) { 44631143d5dSDavid Howells case -EDQUOT: 44731143d5dSDavid Howells case -ENOSPC: 44831143d5dSDavid Howells set_bit(AS_ENOSPC, 44931143d5dSDavid Howells &wb->vnode->vfs_inode.i_mapping->flags); 45031143d5dSDavid Howells break; 45131143d5dSDavid Howells case -EROFS: 45231143d5dSDavid Howells case -EIO: 45331143d5dSDavid Howells case -EREMOTEIO: 45431143d5dSDavid Howells case -EFBIG: 45531143d5dSDavid Howells case -ENOENT: 45631143d5dSDavid Howells case -ENOMEDIUM: 45731143d5dSDavid Howells case -ENXIO: 45831143d5dSDavid Howells afs_kill_pages(wb->vnode, true, first, last); 45931143d5dSDavid Howells set_bit(AS_EIO, &wb->vnode->vfs_inode.i_mapping->flags); 46031143d5dSDavid Howells break; 46131143d5dSDavid Howells case -EACCES: 46231143d5dSDavid Howells case -EPERM: 46331143d5dSDavid Howells case -ENOKEY: 46431143d5dSDavid Howells case -EKEYEXPIRED: 46531143d5dSDavid Howells case -EKEYREJECTED: 46631143d5dSDavid Howells case -EKEYREVOKED: 46731143d5dSDavid Howells afs_kill_pages(wb->vnode, false, first, last); 46831143d5dSDavid Howells break; 46931143d5dSDavid Howells default: 47031143d5dSDavid Howells break; 47131143d5dSDavid Howells } 47231143d5dSDavid Howells } else { 47331143d5dSDavid Howells ret = count; 47431143d5dSDavid Howells } 47531143d5dSDavid Howells 47631143d5dSDavid Howells _leave(" = %d", ret); 47731143d5dSDavid Howells return ret; 47831143d5dSDavid Howells } 47931143d5dSDavid Howells 48031143d5dSDavid Howells /* 48131143d5dSDavid Howells * write a page back to the server 48231143d5dSDavid Howells * - the caller locked the page for us 48331143d5dSDavid Howells */ 48431143d5dSDavid Howells int afs_writepage(struct page *page, struct writeback_control *wbc) 48531143d5dSDavid Howells { 48631143d5dSDavid Howells struct backing_dev_info *bdi = page->mapping->backing_dev_info; 48731143d5dSDavid Howells struct afs_writeback *wb; 48831143d5dSDavid Howells int ret; 48931143d5dSDavid Howells 49031143d5dSDavid Howells _enter("{%lx},", page->index); 49131143d5dSDavid Howells 49231143d5dSDavid Howells wb = (struct afs_writeback *) page_private(page); 49331143d5dSDavid Howells ASSERT(wb != NULL); 49431143d5dSDavid Howells 49531143d5dSDavid Howells ret = afs_write_back_from_locked_page(wb, page); 49631143d5dSDavid Howells unlock_page(page); 49731143d5dSDavid Howells if (ret < 0) { 49831143d5dSDavid Howells _leave(" = %d", ret); 49931143d5dSDavid Howells return 0; 50031143d5dSDavid Howells } 50131143d5dSDavid Howells 50231143d5dSDavid Howells wbc->nr_to_write -= ret; 50331143d5dSDavid Howells if (wbc->nonblocking && bdi_write_congested(bdi)) 50431143d5dSDavid Howells wbc->encountered_congestion = 1; 50531143d5dSDavid Howells 50631143d5dSDavid Howells _leave(" = 0"); 50731143d5dSDavid Howells return 0; 50831143d5dSDavid Howells } 50931143d5dSDavid Howells 51031143d5dSDavid Howells /* 51131143d5dSDavid Howells * write a region of pages back to the server 51231143d5dSDavid Howells */ 51331143d5dSDavid Howells int afs_writepages_region(struct address_space *mapping, 51431143d5dSDavid Howells struct writeback_control *wbc, 51531143d5dSDavid Howells pgoff_t index, pgoff_t end, pgoff_t *_next) 51631143d5dSDavid Howells { 51731143d5dSDavid Howells struct backing_dev_info *bdi = mapping->backing_dev_info; 51831143d5dSDavid Howells struct afs_writeback *wb; 51931143d5dSDavid Howells struct page *page; 52031143d5dSDavid Howells int ret, n; 52131143d5dSDavid Howells 52231143d5dSDavid Howells _enter(",,%lx,%lx,", index, end); 52331143d5dSDavid Howells 52431143d5dSDavid Howells do { 52531143d5dSDavid Howells n = find_get_pages_tag(mapping, &index, PAGECACHE_TAG_DIRTY, 52631143d5dSDavid Howells 1, &page); 52731143d5dSDavid Howells if (!n) 52831143d5dSDavid Howells break; 52931143d5dSDavid Howells 53031143d5dSDavid Howells _debug("wback %lx", page->index); 53131143d5dSDavid Howells 53231143d5dSDavid Howells if (page->index > end) { 53331143d5dSDavid Howells *_next = index; 53431143d5dSDavid Howells page_cache_release(page); 53531143d5dSDavid Howells _leave(" = 0 [%lx]", *_next); 53631143d5dSDavid Howells return 0; 53731143d5dSDavid Howells } 53831143d5dSDavid Howells 53931143d5dSDavid Howells /* at this point we hold neither mapping->tree_lock nor lock on 54031143d5dSDavid Howells * the page itself: the page may be truncated or invalidated 54131143d5dSDavid Howells * (changing page->mapping to NULL), or even swizzled back from 54231143d5dSDavid Howells * swapper_space to tmpfs file mapping 54331143d5dSDavid Howells */ 54431143d5dSDavid Howells lock_page(page); 54531143d5dSDavid Howells 54631143d5dSDavid Howells if (page->mapping != mapping) { 54731143d5dSDavid Howells unlock_page(page); 54831143d5dSDavid Howells page_cache_release(page); 54931143d5dSDavid Howells continue; 55031143d5dSDavid Howells } 55131143d5dSDavid Howells 55231143d5dSDavid Howells if (wbc->sync_mode != WB_SYNC_NONE) 55331143d5dSDavid Howells wait_on_page_writeback(page); 55431143d5dSDavid Howells 55531143d5dSDavid Howells if (PageWriteback(page) || !PageDirty(page)) { 55631143d5dSDavid Howells unlock_page(page); 55731143d5dSDavid Howells continue; 55831143d5dSDavid Howells } 55931143d5dSDavid Howells 56031143d5dSDavid Howells wb = (struct afs_writeback *) page_private(page); 56131143d5dSDavid Howells ASSERT(wb != NULL); 56231143d5dSDavid Howells 56331143d5dSDavid Howells spin_lock(&wb->vnode->writeback_lock); 56431143d5dSDavid Howells wb->state = AFS_WBACK_WRITING; 56531143d5dSDavid Howells spin_unlock(&wb->vnode->writeback_lock); 56631143d5dSDavid Howells 56731143d5dSDavid Howells ret = afs_write_back_from_locked_page(wb, page); 56831143d5dSDavid Howells unlock_page(page); 56931143d5dSDavid Howells page_cache_release(page); 57031143d5dSDavid Howells if (ret < 0) { 57131143d5dSDavid Howells _leave(" = %d", ret); 57231143d5dSDavid Howells return ret; 57331143d5dSDavid Howells } 57431143d5dSDavid Howells 57531143d5dSDavid Howells wbc->nr_to_write -= ret; 57631143d5dSDavid Howells 57731143d5dSDavid Howells if (wbc->nonblocking && bdi_write_congested(bdi)) { 57831143d5dSDavid Howells wbc->encountered_congestion = 1; 57931143d5dSDavid Howells break; 58031143d5dSDavid Howells } 58131143d5dSDavid Howells 58231143d5dSDavid Howells cond_resched(); 58331143d5dSDavid Howells } while (index < end && wbc->nr_to_write > 0); 58431143d5dSDavid Howells 58531143d5dSDavid Howells *_next = index; 58631143d5dSDavid Howells _leave(" = 0 [%lx]", *_next); 58731143d5dSDavid Howells return 0; 58831143d5dSDavid Howells } 58931143d5dSDavid Howells 59031143d5dSDavid Howells /* 59131143d5dSDavid Howells * write some of the pending data back to the server 59231143d5dSDavid Howells */ 59331143d5dSDavid Howells int afs_writepages(struct address_space *mapping, 59431143d5dSDavid Howells struct writeback_control *wbc) 59531143d5dSDavid Howells { 59631143d5dSDavid Howells struct backing_dev_info *bdi = mapping->backing_dev_info; 59731143d5dSDavid Howells pgoff_t start, end, next; 59831143d5dSDavid Howells int ret; 59931143d5dSDavid Howells 60031143d5dSDavid Howells _enter(""); 60131143d5dSDavid Howells 60231143d5dSDavid Howells if (wbc->nonblocking && bdi_write_congested(bdi)) { 60331143d5dSDavid Howells wbc->encountered_congestion = 1; 60431143d5dSDavid Howells _leave(" = 0 [congest]"); 60531143d5dSDavid Howells return 0; 60631143d5dSDavid Howells } 60731143d5dSDavid Howells 60831143d5dSDavid Howells if (wbc->range_cyclic) { 60931143d5dSDavid Howells start = mapping->writeback_index; 61031143d5dSDavid Howells end = -1; 61131143d5dSDavid Howells ret = afs_writepages_region(mapping, wbc, start, end, &next); 61231143d5dSDavid Howells if (start > 0 && wbc->nr_to_write > 0 && ret == 0 && 61331143d5dSDavid Howells !(wbc->nonblocking && wbc->encountered_congestion)) 61431143d5dSDavid Howells ret = afs_writepages_region(mapping, wbc, 0, start, 61531143d5dSDavid Howells &next); 61631143d5dSDavid Howells mapping->writeback_index = next; 61731143d5dSDavid Howells } else if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) { 61831143d5dSDavid Howells end = (pgoff_t)(LLONG_MAX >> PAGE_CACHE_SHIFT); 61931143d5dSDavid Howells ret = afs_writepages_region(mapping, wbc, 0, end, &next); 62031143d5dSDavid Howells if (wbc->nr_to_write > 0) 62131143d5dSDavid Howells mapping->writeback_index = next; 62231143d5dSDavid Howells } else { 62331143d5dSDavid Howells start = wbc->range_start >> PAGE_CACHE_SHIFT; 62431143d5dSDavid Howells end = wbc->range_end >> PAGE_CACHE_SHIFT; 62531143d5dSDavid Howells ret = afs_writepages_region(mapping, wbc, start, end, &next); 62631143d5dSDavid Howells } 62731143d5dSDavid Howells 62831143d5dSDavid Howells _leave(" = %d", ret); 62931143d5dSDavid Howells return ret; 63031143d5dSDavid Howells } 63131143d5dSDavid Howells 63231143d5dSDavid Howells /* 63331143d5dSDavid Howells * write an inode back 63431143d5dSDavid Howells */ 63531143d5dSDavid Howells int afs_write_inode(struct inode *inode, int sync) 63631143d5dSDavid Howells { 63731143d5dSDavid Howells struct afs_vnode *vnode = AFS_FS_I(inode); 63831143d5dSDavid Howells int ret; 63931143d5dSDavid Howells 64031143d5dSDavid Howells _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode); 64131143d5dSDavid Howells 64231143d5dSDavid Howells ret = 0; 64331143d5dSDavid Howells if (sync) { 64431143d5dSDavid Howells ret = filemap_fdatawait(inode->i_mapping); 64531143d5dSDavid Howells if (ret < 0) 64631143d5dSDavid Howells __mark_inode_dirty(inode, I_DIRTY_DATASYNC); 64731143d5dSDavid Howells } 64831143d5dSDavid Howells 64931143d5dSDavid Howells _leave(" = %d", ret); 65031143d5dSDavid Howells return ret; 65131143d5dSDavid Howells } 65231143d5dSDavid Howells 65331143d5dSDavid Howells /* 65431143d5dSDavid Howells * completion of write to server 65531143d5dSDavid Howells */ 65631143d5dSDavid Howells void afs_pages_written_back(struct afs_vnode *vnode, struct afs_call *call) 65731143d5dSDavid Howells { 65831143d5dSDavid Howells struct afs_writeback *wb = call->wb; 65931143d5dSDavid Howells struct pagevec pv; 66031143d5dSDavid Howells unsigned count, loop; 66131143d5dSDavid Howells pgoff_t first = call->first, last = call->last; 66231143d5dSDavid Howells bool free_wb; 66331143d5dSDavid Howells 66431143d5dSDavid Howells _enter("{%x:%u},{%lx-%lx}", 66531143d5dSDavid Howells vnode->fid.vid, vnode->fid.vnode, first, last); 66631143d5dSDavid Howells 66731143d5dSDavid Howells ASSERT(wb != NULL); 66831143d5dSDavid Howells 66931143d5dSDavid Howells pagevec_init(&pv, 0); 67031143d5dSDavid Howells 67131143d5dSDavid Howells do { 6725bbf5d39SDavid Howells _debug("done %lx-%lx", first, last); 67331143d5dSDavid Howells 67431143d5dSDavid Howells count = last - first + 1; 67531143d5dSDavid Howells if (count > PAGEVEC_SIZE) 67631143d5dSDavid Howells count = PAGEVEC_SIZE; 67731143d5dSDavid Howells pv.nr = find_get_pages_contig(call->mapping, first, count, 67831143d5dSDavid Howells pv.pages); 67931143d5dSDavid Howells ASSERTCMP(pv.nr, ==, count); 68031143d5dSDavid Howells 68131143d5dSDavid Howells spin_lock(&vnode->writeback_lock); 68231143d5dSDavid Howells for (loop = 0; loop < count; loop++) { 68331143d5dSDavid Howells struct page *page = pv.pages[loop]; 68431143d5dSDavid Howells end_page_writeback(page); 68531143d5dSDavid Howells if (page_private(page) == (unsigned long) wb) { 68631143d5dSDavid Howells set_page_private(page, 0); 68731143d5dSDavid Howells ClearPagePrivate(page); 68831143d5dSDavid Howells wb->usage--; 68931143d5dSDavid Howells } 69031143d5dSDavid Howells } 69131143d5dSDavid Howells free_wb = false; 69231143d5dSDavid Howells if (wb->usage == 0) { 69331143d5dSDavid Howells afs_unlink_writeback(wb); 69431143d5dSDavid Howells free_wb = true; 69531143d5dSDavid Howells } 69631143d5dSDavid Howells spin_unlock(&vnode->writeback_lock); 69731143d5dSDavid Howells first += count; 69831143d5dSDavid Howells if (free_wb) { 69931143d5dSDavid Howells afs_free_writeback(wb); 70031143d5dSDavid Howells wb = NULL; 70131143d5dSDavid Howells } 70231143d5dSDavid Howells 70331143d5dSDavid Howells __pagevec_release(&pv); 7045bbf5d39SDavid Howells } while (first <= last); 70531143d5dSDavid Howells 70631143d5dSDavid Howells _leave(""); 70731143d5dSDavid Howells } 70831143d5dSDavid Howells 70931143d5dSDavid Howells /* 71031143d5dSDavid Howells * write to an AFS file 71131143d5dSDavid Howells */ 71231143d5dSDavid Howells ssize_t afs_file_write(struct kiocb *iocb, const struct iovec *iov, 71331143d5dSDavid Howells unsigned long nr_segs, loff_t pos) 71431143d5dSDavid Howells { 71531143d5dSDavid Howells struct dentry *dentry = iocb->ki_filp->f_path.dentry; 71631143d5dSDavid Howells struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode); 71731143d5dSDavid Howells ssize_t result; 71831143d5dSDavid Howells size_t count = iov_length(iov, nr_segs); 71931143d5dSDavid Howells int ret; 72031143d5dSDavid Howells 72131143d5dSDavid Howells _enter("{%x.%u},{%zu},%lu,", 72231143d5dSDavid Howells vnode->fid.vid, vnode->fid.vnode, count, nr_segs); 72331143d5dSDavid Howells 72431143d5dSDavid Howells if (IS_SWAPFILE(&vnode->vfs_inode)) { 72531143d5dSDavid Howells printk(KERN_INFO 72631143d5dSDavid Howells "AFS: Attempt to write to active swap file!\n"); 72731143d5dSDavid Howells return -EBUSY; 72831143d5dSDavid Howells } 72931143d5dSDavid Howells 73031143d5dSDavid Howells if (!count) 73131143d5dSDavid Howells return 0; 73231143d5dSDavid Howells 73331143d5dSDavid Howells result = generic_file_aio_write(iocb, iov, nr_segs, pos); 73431143d5dSDavid Howells if (IS_ERR_VALUE(result)) { 73531143d5dSDavid Howells _leave(" = %zd", result); 73631143d5dSDavid Howells return result; 73731143d5dSDavid Howells } 73831143d5dSDavid Howells 73931143d5dSDavid Howells /* return error values for O_SYNC and IS_SYNC() */ 74031143d5dSDavid Howells if (IS_SYNC(&vnode->vfs_inode) || iocb->ki_filp->f_flags & O_SYNC) { 74131143d5dSDavid Howells ret = afs_fsync(iocb->ki_filp, dentry, 1); 74231143d5dSDavid Howells if (ret < 0) 74331143d5dSDavid Howells result = ret; 74431143d5dSDavid Howells } 74531143d5dSDavid Howells 74631143d5dSDavid Howells _leave(" = %zd", result); 74731143d5dSDavid Howells return result; 74831143d5dSDavid Howells } 74931143d5dSDavid Howells 75031143d5dSDavid Howells /* 75131143d5dSDavid Howells * flush the vnode to the fileserver 75231143d5dSDavid Howells */ 75331143d5dSDavid Howells int afs_writeback_all(struct afs_vnode *vnode) 75431143d5dSDavid Howells { 75531143d5dSDavid Howells struct address_space *mapping = vnode->vfs_inode.i_mapping; 75631143d5dSDavid Howells struct writeback_control wbc = { 75731143d5dSDavid Howells .bdi = mapping->backing_dev_info, 75831143d5dSDavid Howells .sync_mode = WB_SYNC_ALL, 75931143d5dSDavid Howells .nr_to_write = LONG_MAX, 76031143d5dSDavid Howells .for_writepages = 1, 76131143d5dSDavid Howells .range_cyclic = 1, 76231143d5dSDavid Howells }; 76331143d5dSDavid Howells int ret; 76431143d5dSDavid Howells 76531143d5dSDavid Howells _enter(""); 76631143d5dSDavid Howells 76731143d5dSDavid Howells ret = mapping->a_ops->writepages(mapping, &wbc); 76831143d5dSDavid Howells __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); 76931143d5dSDavid Howells 77031143d5dSDavid Howells _leave(" = %d", ret); 77131143d5dSDavid Howells return ret; 77231143d5dSDavid Howells } 77331143d5dSDavid Howells 77431143d5dSDavid Howells /* 77531143d5dSDavid Howells * flush any dirty pages for this process, and check for write errors. 77631143d5dSDavid Howells * - the return status from this call provides a reliable indication of 77731143d5dSDavid Howells * whether any write errors occurred for this process. 77831143d5dSDavid Howells */ 77931143d5dSDavid Howells int afs_fsync(struct file *file, struct dentry *dentry, int datasync) 78031143d5dSDavid Howells { 78131143d5dSDavid Howells struct afs_writeback *wb, *xwb; 78231143d5dSDavid Howells struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode); 78331143d5dSDavid Howells int ret; 78431143d5dSDavid Howells 78531143d5dSDavid Howells _enter("{%x:%u},{n=%s},%d", 78631143d5dSDavid Howells vnode->fid.vid, vnode->fid.vnode, dentry->d_name.name, 78731143d5dSDavid Howells datasync); 78831143d5dSDavid Howells 78931143d5dSDavid Howells /* use a writeback record as a marker in the queue - when this reaches 79031143d5dSDavid Howells * the front of the queue, all the outstanding writes are either 79131143d5dSDavid Howells * completed or rejected */ 79231143d5dSDavid Howells wb = kzalloc(sizeof(*wb), GFP_KERNEL); 79331143d5dSDavid Howells if (!wb) 79431143d5dSDavid Howells return -ENOMEM; 79531143d5dSDavid Howells wb->vnode = vnode; 79631143d5dSDavid Howells wb->first = 0; 79731143d5dSDavid Howells wb->last = -1; 79831143d5dSDavid Howells wb->offset_first = 0; 79931143d5dSDavid Howells wb->to_last = PAGE_SIZE; 80031143d5dSDavid Howells wb->usage = 1; 80131143d5dSDavid Howells wb->state = AFS_WBACK_SYNCING; 80231143d5dSDavid Howells init_waitqueue_head(&wb->waitq); 80331143d5dSDavid Howells 80431143d5dSDavid Howells spin_lock(&vnode->writeback_lock); 80531143d5dSDavid Howells list_for_each_entry(xwb, &vnode->writebacks, link) { 80631143d5dSDavid Howells if (xwb->state == AFS_WBACK_PENDING) 80731143d5dSDavid Howells xwb->state = AFS_WBACK_CONFLICTING; 80831143d5dSDavid Howells } 80931143d5dSDavid Howells list_add_tail(&wb->link, &vnode->writebacks); 81031143d5dSDavid Howells spin_unlock(&vnode->writeback_lock); 81131143d5dSDavid Howells 81231143d5dSDavid Howells /* push all the outstanding writebacks to the server */ 81331143d5dSDavid Howells ret = afs_writeback_all(vnode); 81431143d5dSDavid Howells if (ret < 0) { 81531143d5dSDavid Howells afs_put_writeback(wb); 81631143d5dSDavid Howells _leave(" = %d [wb]", ret); 81731143d5dSDavid Howells return ret; 81831143d5dSDavid Howells } 81931143d5dSDavid Howells 82031143d5dSDavid Howells /* wait for the preceding writes to actually complete */ 82131143d5dSDavid Howells ret = wait_event_interruptible(wb->waitq, 82231143d5dSDavid Howells wb->state == AFS_WBACK_COMPLETE || 82331143d5dSDavid Howells vnode->writebacks.next == &wb->link); 82431143d5dSDavid Howells afs_put_writeback(wb); 82531143d5dSDavid Howells _leave(" = %d", ret); 82631143d5dSDavid Howells return ret; 82731143d5dSDavid Howells } 828