@@ -129,7 +129,8 @@ static int cachefiles_daemon_add_cache(struct cachefiles_cache *cache)
!root->d_inode->i_op->setxattr ||
!root->d_inode->i_op->getxattr ||
!root->d_sb->s_op->statfs ||
- !root->d_sb->s_op->sync_fs)
+ !root->d_sb->s_op->sync_fs ||
+ !root->d_sb->s_type->fs_flags & FS_SUPPORTS_SEEK_HOLE)
goto error_unsupported;
ret = -EROFS;
@@ -402,7 +402,7 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op,
cache = container_of(object->fscache.cache,
struct cachefiles_cache, cache);
- _enter("{%p},{%lx},,,", object, page->index);
+ kenter("{%p},{%lx},,,", object, page->index);
if (!object->backer)
goto enobufs;
@@ -462,12 +462,12 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op,
goto enobufs;
}
- _leave(" = %d", ret);
+ kleave(" = %d", ret);
return ret;
enobufs:
fscache_retrieval_complete(op, 1);
- _leave(" = -ENOBUFS");
+ kleave(" = -ENOBUFS");
return -ENOBUFS;
}
@@ -698,7 +698,10 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op,
struct pagevec pagevec;
struct inode *inode;
struct page *page, *_n;
+ struct file *file;
+ struct path path;
unsigned nrbackpages;
+ loff_t pre_hole, from, to;
int ret, ret2, space;
object = container_of(op->op.object,
@@ -706,7 +709,7 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op,
cache = container_of(object->fscache.cache,
struct cachefiles_cache, cache);
- _enter("{OBJ%x,%d},,%d,,",
+ kenter("{OBJ%x,%d},,%d,,",
object->fscache.debug_id, atomic_read(&op->op.usage),
*nr_pages);
@@ -731,47 +734,34 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op,
INIT_LIST_HEAD(&backpages);
nrbackpages = 0;
+ path.mnt = cache->mnt;
+ path.dentry = object->backer;
+ file = dentry_open(&path, O_RDWR, cache->cache_cred);
+ if (IS_ERR(file))
+ goto all_enobufs;
+ pre_hole = from = to = 0;
+
ret = space ? -ENODATA : -ENOBUFS;
- list_for_each_entry_safe(page, _n, pages, lru) {
- bool have_data;
-
- if (inode->i_sb->s_type->fs_flags & FS_SUPPORTS_SEEK_HOLE) {
- /* Use llseek */
- struct path path;
- struct file *file;
- loff_t addr;
-
- path.mnt = cache->mnt;
- path.dentry = object->backer;
- file = dentry_open(&path, O_RDONLY, cache->cache_cred);
- if (IS_ERR(file))
+ list_for_each_entry_safe_reverse(page, _n, pages, lru) {
+ loff_t addr;
+
+ /* Determine whether the page is present */
+ addr = page->index;
+ addr <<= PAGE_SHIFT;
+ if (addr < pre_hole || addr >= to) {
+ pre_hole = addr;
+ from = vfs_llseek(file, pre_hole, SEEK_DATA);
+ kdebug("SEEK_DATA: %llx", from);
+ if (IS_ERR_VALUE(from))
+ goto all_enobufs;
+
+ to = vfs_llseek(file, from, SEEK_HOLE);
+ kdebug("SEEK_HOLE: %llx", to);
+ if (IS_ERR_VALUE(to))
goto all_enobufs;
- addr = page->index;
- addr <<= PAGE_SHIFT;
- have_date = (addr == vfs_llseek(file, addr, SEEK_DATA));
- filp_close(file, NULL);
- } else {
- /* we assume the absence or presence of the first block is a
- * good enough indication for the page as a whole
- * - TODO: don't use bmap() for this as it is _not_ actually
- * good enough for this as it doesn't indicate errors, but
- * it's all we've got for the moment
- */
- /* calculate the shift required to use bmap */
- unsigned shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits;
- sector_t block0, block;
-
- block0 = page->index;
- block0 <<= shift;
-
- block = inode->i_mapping->a_ops->bmap(inode->i_mapping,
- block0);
- _debug("%llx -> %llx",
- (unsigned long long) block0,
- (unsigned long long) block);
- have_data = (block != 0);
}
- if (have_data) {
+
+ if (addr >= from && addr <= to - PAGE_SIZE) {
/* we have data - add it to the list to give to the
* backing fs */
list_move(&page->lru, &backpages);
@@ -786,6 +776,8 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op,
}
}
+ filp_close(file, NULL);
+
if (pagevec_count(&pagevec) > 0)
fscache_mark_pages_cached(op, &pagevec);
@@ -800,12 +792,13 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op,
ret = ret2;
}
- _leave(" = %d [nr=%u%s]",
+ kleave(" = %d [nr=%u%s]",
ret, *nr_pages, list_empty(pages) ? " empty" : "");
return ret;
all_enobufs:
fscache_retrieval_complete(op, *nr_pages);
+ kleave(" = -ENOBUFS [all]");
return -ENOBUFS;
}
@@ -89,7 +89,7 @@ static struct file_system_type ext2_fs_type = {
.name = "ext2",
.mount = ext4_mount,
.kill_sb = kill_block_super,
- .fs_flags = FS_REQUIRES_DEV,
+ .fs_flags = FS_REQUIRES_DEV | FS_SUPPORTS_SEEK_HOLE,
};
MODULE_ALIAS_FS("ext2");
MODULE_ALIAS("ext2");