From: Nick Piggin <npiggin@suse.de>
To: Andrew Morton <akpm@linux-foundation.org>,
linux-fsdevel@vger.kernel.org, mhalcrow@us.ibm.com,
phillip@hellewell.homeip.net, sfrench@samba.org,
dhowells@redhat.com
Subject: [rfc][patch 3/5] afs: new aops
Date: Mon, 12 Nov 2007 08:14:48 +0100 [thread overview]
Message-ID: <20071112071448.GE22953@wotan.suse.de> (raw)
In-Reply-To: <20071112071245.GB22953@wotan.suse.de>
Convert afs to new aops.
Cannot assume writes will fully complete, so this conversion goes the easy
way and always brings the page uptodate before the write.
Signed-off-by: Nick Piggin <npiggin@suse.de>
---
Index: linux-2.6/fs/afs/file.c
===================================================================
--- linux-2.6.orig/fs/afs/file.c
+++ linux-2.6/fs/afs/file.c
@@ -50,8 +50,8 @@ const struct address_space_operations af
.launder_page = afs_launder_page,
.releasepage = afs_releasepage,
.invalidatepage = afs_invalidatepage,
- .prepare_write = afs_prepare_write,
- .commit_write = afs_commit_write,
+ .write_begin = afs_write_begin,
+ .write_end = afs_write_end,
.writepage = afs_writepage,
.writepages = afs_writepages,
};
Index: linux-2.6/fs/afs/internal.h
===================================================================
--- linux-2.6.orig/fs/afs/internal.h
+++ linux-2.6/fs/afs/internal.h
@@ -731,8 +731,12 @@ extern int afs_volume_release_fileserver
*/
extern int afs_set_page_dirty(struct page *);
extern void afs_put_writeback(struct afs_writeback *);
-extern int afs_prepare_write(struct file *, struct page *, unsigned, unsigned);
-extern int afs_commit_write(struct file *, struct page *, unsigned, unsigned);
+extern int afs_write_begin(struct file *file, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned flags,
+ struct page **pagep, void **fsdata);
+extern int afs_write_end(struct file *file, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned copied,
+ struct page *page, void *fsdata);
extern int afs_writepage(struct page *, struct writeback_control *);
extern int afs_writepages(struct address_space *, struct writeback_control *);
extern int afs_write_inode(struct inode *, int);
Index: linux-2.6/fs/afs/write.c
===================================================================
--- linux-2.6.orig/fs/afs/write.c
+++ linux-2.6/fs/afs/write.c
@@ -84,15 +84,23 @@ void afs_put_writeback(struct afs_writeb
* partly or wholly fill a page that's under preparation for writing
*/
static int afs_fill_page(struct afs_vnode *vnode, struct key *key,
- unsigned start, unsigned len, struct page *page)
+ loff_t pos, unsigned len, struct page *page)
{
+ loff_t i_size;
+ unsigned eof;
int ret;
- _enter(",,%u,%u", start, len);
+ _enter(",,%llu,%u", (unsigned long long)pos, len);
- ASSERTCMP(start + len, <=, PAGE_SIZE);
+ ASSERTCMP(len, <=, PAGE_CACHE_SIZE);
- ret = afs_vnode_fetch_data(vnode, key, start, len, page);
+ i_size = i_size_read(&vnode->vfs_inode);
+ if (pos + len > i_size)
+ eof = i_size;
+ else
+ eof = PAGE_CACHE_SIZE;
+
+ ret = afs_vnode_fetch_data(vnode, key, 0, eof, page);
if (ret < 0) {
if (ret == -ENOENT) {
_debug("got NOENT from server"
@@ -107,109 +115,55 @@ static int afs_fill_page(struct afs_vnod
}
/*
- * prepare a page for being written to
- */
-static int afs_prepare_page(struct afs_vnode *vnode, struct page *page,
- struct key *key, unsigned offset, unsigned to)
-{
- unsigned eof, tail, start, stop, len;
- loff_t i_size, pos;
- void *p;
- int ret;
-
- _enter("");
-
- if (offset == 0 && to == PAGE_SIZE)
- return 0;
-
- p = kmap_atomic(page, KM_USER0);
-
- i_size = i_size_read(&vnode->vfs_inode);
- pos = (loff_t) page->index << PAGE_SHIFT;
- if (pos >= i_size) {
- /* partial write, page beyond EOF */
- _debug("beyond");
- if (offset > 0)
- memset(p, 0, offset);
- if (to < PAGE_SIZE)
- memset(p + to, 0, PAGE_SIZE - to);
- kunmap_atomic(p, KM_USER0);
- return 0;
- }
-
- if (i_size - pos >= PAGE_SIZE) {
- /* partial write, page entirely before EOF */
- _debug("before");
- tail = eof = PAGE_SIZE;
- } else {
- /* partial write, page overlaps EOF */
- eof = i_size - pos;
- _debug("overlap %u", eof);
- tail = max(eof, to);
- if (tail < PAGE_SIZE)
- memset(p + tail, 0, PAGE_SIZE - tail);
- if (offset > eof)
- memset(p + eof, 0, PAGE_SIZE - eof);
- }
-
- kunmap_atomic(p, KM_USER0);
-
- ret = 0;
- if (offset > 0 || eof > to) {
- /* need to fill one or two bits that aren't going to be written
- * (cover both fillers in one read if there are two) */
- start = (offset > 0) ? 0 : to;
- stop = (eof > to) ? eof : offset;
- len = stop - start;
- _debug("wr=%u-%u av=0-%u rd=%u@%u",
- offset, to, eof, start, len);
- ret = afs_fill_page(vnode, key, start, len, page);
- }
-
- _leave(" = %d", ret);
- return ret;
-}
-
-/*
* prepare to perform part of a write to a page
- * - the caller holds the page locked, preventing it from being written out or
- * modified by anyone else
*/
-int afs_prepare_write(struct file *file, struct page *page,
- unsigned offset, unsigned to)
+int afs_write_begin(struct file *file, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned flags,
+ struct page **pagep, void **fsdata)
{
+ struct page *page;
struct afs_writeback *candidate, *wb;
struct afs_vnode *vnode = AFS_FS_I(file->f_dentry->d_inode);
struct key *key = file->private_data;
- pgoff_t index;
+ pgoff_t index = pos >> PAGE_CACHE_SHIFT;
+ unsigned from = pos & (PAGE_CACHE_SIZE - 1);
+ unsigned to = from + len;
int ret;
_enter("{%x:%u},{%lx},%u,%u",
- vnode->fid.vid, vnode->fid.vnode, page->index, offset, to);
+ vnode->fid.vid, vnode->fid.vnode, index, from, to);
candidate = kzalloc(sizeof(*candidate), GFP_KERNEL);
if (!candidate)
return -ENOMEM;
candidate->vnode = vnode;
- candidate->first = candidate->last = page->index;
- candidate->offset_first = offset;
+ candidate->first = candidate->last = index;
+ candidate->offset_first = from;
candidate->to_last = to;
candidate->usage = 1;
candidate->state = AFS_WBACK_PENDING;
init_waitqueue_head(&candidate->waitq);
+ page = __grab_cache_page(mapping, index);
+ if (!page) {
+ kfree(candidate);
+ return -ENOMEM;
+ }
+ *pagep = page;
+ /* page won't leak in error case: it eventually gets cleaned off LRU */
+
if (!PageUptodate(page)) {
_debug("not up to date");
- ret = afs_prepare_page(vnode, page, key, offset, to);
+ ret = afs_fill_page(vnode, key, pos, len, page);
if (ret < 0) {
kfree(candidate);
_leave(" = %d [prep]", ret);
return ret;
}
+ SetPageUptodate(page);
}
try_again:
- index = page->index;
spin_lock(&vnode->writeback_lock);
/* see if this page is already pending a writeback under a suitable key
@@ -242,8 +196,8 @@ try_again:
subsume_in_current_wb:
_debug("subsume");
ASSERTRANGE(wb->first, <=, index, <=, wb->last);
- if (index == wb->first && offset < wb->offset_first)
- wb->offset_first = offset;
+ if (index == wb->first && from < wb->offset_first)
+ wb->offset_first = from;
if (index == wb->last && to > wb->to_last)
wb->to_last = to;
spin_unlock(&vnode->writeback_lock);
@@ -289,17 +243,17 @@ flush_conflicting_wb:
/*
* finalise part of a write to a page
*/
-int afs_commit_write(struct file *file, struct page *page,
- unsigned offset, unsigned to)
+int afs_write_end(struct file *file, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned copied,
+ struct page *page, void *fsdata)
{
struct afs_vnode *vnode = AFS_FS_I(file->f_dentry->d_inode);
loff_t i_size, maybe_i_size;
- _enter("{%x:%u},{%lx},%u,%u",
- vnode->fid.vid, vnode->fid.vnode, page->index, offset, to);
+ _enter("{%x:%u},{%lx}",
+ vnode->fid.vid, vnode->fid.vnode, page->index);
- maybe_i_size = (loff_t) page->index << PAGE_SHIFT;
- maybe_i_size += to;
+ maybe_i_size = pos + copied;
i_size = i_size_read(&vnode->vfs_inode);
if (maybe_i_size > i_size) {
@@ -310,12 +264,13 @@ int afs_commit_write(struct file *file,
spin_unlock(&vnode->writeback_lock);
}
- SetPageUptodate(page);
set_page_dirty(page);
if (PageDirty(page))
_debug("dirtied");
+ unlock_page(page);
+ page_cache_release(page);
- return 0;
+ return copied;
}
/*
next prev parent reply other threads:[~2007-11-12 7:14 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-11-12 7:12 [rfc][patches] remove ->prepare_write Nick Piggin
2007-11-12 7:13 ` [rfc][patch 1/5] ecryptfs new aops Nick Piggin
2007-11-12 7:14 ` [rfc][patch 2/5] cifs: " Nick Piggin
2007-11-12 7:14 ` Nick Piggin [this message]
2007-11-12 7:20 ` [rfc][patch 4/5] rd: rewrite rd Nick Piggin
2007-11-12 7:23 ` [rfc][patch 5/5] remove prepare_write Nick Piggin
2007-11-12 15:29 ` [rfc][patch 3/5] afs: new aops David Howells
2007-11-13 0:15 ` Nick Piggin
2007-11-13 0:30 ` David Howells
2007-11-13 0:44 ` Nick Piggin
2007-11-13 10:56 ` David Howells
2007-11-14 4:24 ` Nick Piggin
2007-11-14 12:18 ` David Howells
2007-11-14 15:18 ` Nick Piggin
2007-11-14 15:57 ` David Howells
2007-11-14 21:32 ` Nick Piggin
2007-11-15 12:15 ` David Howells
2007-11-15 21:37 ` Nick Piggin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20071112071448.GE22953@wotan.suse.de \
--to=npiggin@suse.de \
--cc=akpm@linux-foundation.org \
--cc=dhowells@redhat.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=mhalcrow@us.ibm.com \
--cc=phillip@hellewell.homeip.net \
--cc=sfrench@samba.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).