summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Morton <akpm@digeo.com>2002-10-28 16:22:07 -0800
committerJens Axboe <axboe@suse.de>2002-10-28 16:22:07 -0800
commit303c9cf648d3e5f648afe89d624cc3e3c8d5ce71 (patch)
tree2f83577b40e2a0abd54853934481b0f0a19c2fec
parent3ee477f0d419d10cdd72ac9b7d7e9e7cc95e99f0 (diff)
[PATCH] libfs a_ops correctnes
simple_prepare_write() currently memsets the entire page. It only needs to clear the parts which are outside the to-be-written region. This change makes no difference to performance - that memset was just a cache preload for the copy_from_user() in generic_file_write(). But it's more correct. Also, mark the page dirty in simple_commit_write(), not in simple_prepare_write(). Because the page's contents are changed after prepare_write(). This doesn't matter in practice, but it is setting a bad example. Also, add a flush_dcache_page() to simple_prepare_write(). Again, not really needed because the page cannot be mapped into pagetables if it is not uptodate. But it is example code and should not be missing such things.
-rw-r--r--fs/libfs.c32
1 files changed, 17 insertions, 15 deletions
diff --git a/fs/libfs.c b/fs/libfs.c
index 98c1968b7155..ea1ec8d09310 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -260,7 +260,8 @@ int simple_rmdir(struct inode *dir, struct dentry *dentry)
return 0;
}
-int simple_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry)
+int simple_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry)
{
int they_are_dirs = S_ISDIR(old_dentry->d_inode->i_mode);
@@ -295,29 +296,30 @@ out:
return 0;
}
-int simple_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to)
+int simple_prepare_write(struct file *file, struct page *page,
+ unsigned from, unsigned to)
{
- void *kaddr;
-
- if (PageUptodate(page))
- goto out;
-
- kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr, 0, PAGE_CACHE_SIZE);
- kunmap_atomic(kaddr, KM_USER0);
- SetPageUptodate(page);
-out:
- set_page_dirty(page);
+ if (!PageUptodate(page)) {
+ if (to - from != PAGE_CACHE_SIZE) {
+ void *kaddr = kmap_atomic(page, KM_USER0);
+ memset(kaddr, 0, from);
+ memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
+ flush_dcache_page(page);
+ kunmap_atomic(kaddr, KM_USER0);
+ }
+ SetPageUptodate(page);
+ }
return 0;
}
-int simple_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to)
+int simple_commit_write(struct file *file, struct page *page,
+ unsigned offset, unsigned to)
{
struct inode *inode = page->mapping->host;
loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
if (pos > inode->i_size)
inode->i_size = pos;
-
+ set_page_dirty(page);
return 0;
}