aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cachefiles/rdwr.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2009-11-19 13:11:52 -0500
committerDavid Howells <dhowells@redhat.com>2009-11-19 13:11:52 -0500
commita17754fb8c28af19cd70dcbec6d5b0773b94e0c1 (patch)
treed7c25b217c684153eadbac78ab9b1bbff08b75f6 /fs/cachefiles/rdwr.c
parent868411be3f445a83fafbd734f3e426400138add5 (diff)
CacheFiles: Don't write a full page if there's only a partial page to cache
cachefiles_write_page() writes a full page to the backing file for the last page of the netfs file, even if the netfs file's last page is only a partial page. This causes the EOF on the backing file to be extended beyond the EOF of the netfs, and thus the backing file will be truncated by cachefiles_attr_changed() called from cachefiles_lookup_object(). So we need to limit the write we make to the backing file on that last page such that it doesn't push the EOF too far. Also, if a backing file that has a partial page at the end is expanded, we discard the partial page and refetch it on the basis that we then have a hole in the file with invalid data, and should the power go out... A better way to deal with this could be to record a note that the partial page contains invalid data until the correct data is written into it. This isn't a problem for netfs's that discard the whole backing file if the file size changes (such as NFS). Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'fs/cachefiles/rdwr.c')
-rw-r--r--fs/cachefiles/rdwr.c23
1 files changed, 19 insertions, 4 deletions
diff --git a/fs/cachefiles/rdwr.c b/fs/cachefiles/rdwr.c
index 3304646dae84..5a84fd7109ad 100644
--- a/fs/cachefiles/rdwr.c
+++ b/fs/cachefiles/rdwr.c
@@ -803,7 +803,8 @@ int cachefiles_write_page(struct fscache_storage *op, struct page *page)
803 struct cachefiles_cache *cache; 803 struct cachefiles_cache *cache;
804 mm_segment_t old_fs; 804 mm_segment_t old_fs;
805 struct file *file; 805 struct file *file;
806 loff_t pos; 806 loff_t pos, eof;
807 size_t len;
807 void *data; 808 void *data;
808 int ret; 809 int ret;
809 810
@@ -837,15 +838,29 @@ int cachefiles_write_page(struct fscache_storage *op, struct page *page)
837 ret = -EIO; 838 ret = -EIO;
838 if (file->f_op->write) { 839 if (file->f_op->write) {
839 pos = (loff_t) page->index << PAGE_SHIFT; 840 pos = (loff_t) page->index << PAGE_SHIFT;
841
842 /* we mustn't write more data than we have, so we have
843 * to beware of a partial page at EOF */
844 eof = object->fscache.store_limit_l;
845 len = PAGE_SIZE;
846 if (eof & ~PAGE_MASK) {
847 ASSERTCMP(pos, <, eof);
848 if (eof - pos < PAGE_SIZE) {
849 _debug("cut short %llx to %llx",
850 pos, eof);
851 len = eof - pos;
852 ASSERTCMP(pos + len, ==, eof);
853 }
854 }
855
840 data = kmap(page); 856 data = kmap(page);
841 old_fs = get_fs(); 857 old_fs = get_fs();
842 set_fs(KERNEL_DS); 858 set_fs(KERNEL_DS);
843 ret = file->f_op->write( 859 ret = file->f_op->write(
844 file, (const void __user *) data, PAGE_SIZE, 860 file, (const void __user *) data, len, &pos);
845 &pos);
846 set_fs(old_fs); 861 set_fs(old_fs);
847 kunmap(page); 862 kunmap(page);
848 if (ret != PAGE_SIZE) 863 if (ret != len)
849 ret = -EIO; 864 ret = -EIO;
850 } 865 }
851 fput(file); 866 fput(file);