Allow fscache to work on BTRFS
Subsystems (4)
cover Allow fscache to work on BTRFS
The following three patches allow fs to "cachefiles" in a BTRFS filesystem.
The first is a minor cleanup to cachefiles.
The second is the main change - it teaches cachefile to use lseek(SEEK_DATA) to find allocated blocks in a file, rather than bmap. The third patch simply enables this for btrfs.
Thanks,
NeilBrown
---
NeilBrown (3):
cachefiles: perform test on s_blocksize when opening cache file. fscache/cachefiles: optionally use SEEK_DATA instead of ->bmap.
btrfs: set FS_SUPPORTS_SEEK_HOLE flag.
fs/btrfs/super.c | 3 + fs/cachefiles/namei.c | 13 ++++- fs/cachefiles/rdwr.c | 125 ++++++++++++++++++++++++++++++------------------- include/linux/fs.h | 1 4 files changed, 88 insertions(+), 54 deletions(-)
--
Signature
PATCH 1/3 cachefiles: perform test on s_blocksize when opening cache file.
cachefiles requires that s_blocksize in the cache is not greater than PAGE_SIZE, and performs the check every time a block is accessed.
Move the test to the place where the file is "opened", where other file-validity tests are performed.
--- fs/cachefiles/namei.c | 2 ++ fs/cachefiles/rdwr.c | 6 ------ 2 files changed, 2 insertions(+), 6 deletions(-)
fs/cachefiles/namei.c +2 -0
@@ -649,6 +649,8 @@ lookup_again: aops = object->dentry->d_inode->i_mapping->a_ops;if (!aops->bmap) goto check_error; +if (object->dentry->d_sb->s_blocksize >PAGE_SIZE ) + goto check_error; object->backer = object->dentry; }else {
fs/cachefiles/rdwr.c +0 -6
@@ -414,9 +414,6 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op,ASSERT (inode->i_mapping->a_ops->readpages);/* calculate the shift required to use bmap */ -if (inode->i_sb->s_blocksize >PAGE_SIZE ) - goto enobufs; - shift =PAGE_SHIFT - inode->i_sb->s_blocksize_bits; op->op.flags &=FSCACHE_OP_KEEP_FLAGS ;
@@ -711,9 +708,6 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op,ASSERT (inode->i_mapping->a_ops->readpages);/* calculate the shift required to use bmap */ -if (inode->i_sb->s_blocksize >PAGE_SIZE ) - goto all_enobufs; - shift =PAGE_SHIFT - inode->i_sb->s_blocksize_bits;pagevec_init (&pagevec,0 );
PATCH 2/3 fscache/cachefiles: optionally use SEEK_DATA instead of ->bmap.
In reply to NeilBrowncachefiles currently uses 'bmap' to determine if a given block in a file has been cached, or not.
Not all filesystems support bmap, particularly BTRFS.
SEEK_DATA can be used to determine if a block in a file has been allocated, but not all filesystems support this reliably. On filesystems without explicit report, SEEK_DATA will report anything below i_size to be valid data.
So:
- add a file_system_type flag which confirms that SEEK_DATA and SEEK_HOLE will reliably report holes,
- change cachefiles to use vfs_lseek if FS_SUPPORTS_SEEK_HOLE is set, and only use ->bmap if it isn't.
Subsequent patch will set flag for btrfs. Other filesystems could usefully have FS_SUPPORTS_SEEK_HOLE set, but I'll leave that to the relevant maintainers to decide.
--- fs/cachefiles/namei.c | 15 ++++-- fs/cachefiles/rdwr.c | 119 +++++++++++++++++++++++++++++++------------------ include/linux/fs.h | 1 3 files changed, 86 insertions(+), 49 deletions(-)
fs/cachefiles/namei.c +9 -6
@@ -643,14 +643,17 @@ lookup_again:/* open a file interface onto a data file */ if (object->type !=FSCACHE_COOKIE_TYPE_INDEX ) {if (d_is_reg (object->dentry)) { -const struct address_space_operations *aops; ret = -EPERM ; - aops = object->dentry->d_inode->i_mapping->a_ops; -if (!aops->bmap) - goto check_error; -if (object->dentry->d_sb->s_blocksize >PAGE_SIZE ) - goto check_error; +if (!(object->dentry->d_sb->s_type->fs_flags + &FS_SUPPORTS_SEEK_HOLE )) { +const struct address_space_operations *aops; + aops = object->dentry->d_inode->i_mapping->a_ops; +if (!aops->bmap) + goto check_error; +if (object->dentry->d_sb->s_blocksize >PAGE_SIZE ) + goto check_error; + } object->backer = object->dentry; }else {
fs/cachefiles/rdwr.c +76 -43
158 lines not on this page · raw message
include/linux/fs.h +1 -0
@@ -1863,6 +1863,7 @@ struct file_system_type {#define FS_HAS_SUBTYPE 4#define FS_USERNS_MOUNT 8/* Can be mounted by userns root */ #define FS_USERNS_DEV_MOUNT 16/* A userns mount does not imply MNT_NODEV */ +#define FS_SUPPORTS_SEEK_HOLE 32/* SEEK_HOLE/SEEK_DATA reliably detect holes */ #define FS_RENAME_DOES_D_MOVE 32768/* FS will handle d_move() during rename() internally. */ struct dentry *(*mount) (struct file_system_type *,int ,const char *,void *);
Re: [PATCH 2/3] fscache/cachefiles: optionally use SEEK_DATA instead of ->bmap.
Please just usse SEEK_HOLE/DATA support unconditioanlly. ->bmap is a horrible hack that is completely unsafe.
Re: [PATCH 2/3] fscache/cachefiles: optionally use SEEK_DATA instead of ->bmap.
Quoted 3 lines · On Sun, 19 Apr 2015 23:08:18 -0700 Christoph Hellwig <[email protected]> wrote:
Please just usse SEEK_HOLE/DATA support unconditioanlly. ->bmap is a horrible hack that is completely unsafe.
A worthwhile goal, but I certainly wouldn't consider pursuing it until what I have submitted so far as been accepted - let's not reject "good" while waiting for "perfect".
NeilBrown
Re: [PATCH 2/3] fscache/cachefiles: optionally use SEEK_DATA instead of ->bmap.
Quoted 3 lines · NeilBrown
A worthwhile goal, but I certainly wouldn't consider pursuing it until what I have submitted so far as been accepted - let's not reject "good" while waiting for "perfect".
It's still broken. You add conditional flag for the almost right (almost because the flag in the filesystem type needs to go) while leaving the broken option th default. So what you propose here is not good, it's at best just as bad as the old version because you don't remove broken code but add a lot more clutter at the same time.
Re: [PATCH 2/3] fscache/cachefiles: optionally use SEEK_DATA instead of ->bmap.
Quoted 7 lines · On Mon, 20 Apr 2015 02:45:39 -0700 Christoph Hellwig <[email protected]> wrote:
Quoted 3 lines · NeilBrown
A worthwhile goal, but I certainly wouldn't consider pursuing it until what I have submitted so far as been accepted - let's not reject "good" while waiting for "perfect".
It's still broken. You add conditional flag for the almost right (almost because the flag in the filesystem type needs to go)
Why does it have to go? I suspect you have a reason, but I can't read your mind.
Quoted 2 lines
while
leaving the broken option th default.
You say it is broken, and yet people are using it and are having a degree of success.
Surely the appropriate process is:
- introduce a "better" option
- examine each relevant filesystem and transition over to use the new option.
- remove the "not so good" option.
I'm still at step 1.
Quoted 3 lines
So what you propose here is not
good, it's at best just as bad as the old version because you don't remove broken code but add a lot more clutter at the same time.
What I propose is measurably better because it works with BTRFS now, and there seems to be a reasonable path towards making to generally better if someone cares enough to examine each filesystem.
So I still claim you are pushing back against "good" because you want "perfect".
NeilBrown
David Howells
maintainerRe: [PATCH 2/3] fscache/cachefiles: optionally use SEEK_DATA instead of ->bmap.
In reply to NeilBrownReview int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op,
Quoted 1 line · NeilBrown
(quoted diff) +0
-0@@ -721,24 +733,45 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op,
We can actually do better than this what you've done here for cachefiles_read_or_alloc_pages(). We can use SEEK_DATA to check the beginning of a run of pages and then SEEK_HOLE to see how many pages are covered.
David
David Howells
maintainerRFC PATCH 1/1 cachefiles: Make better use of SEEK_DATA/SEEK_HOLE
Here's a test patch that makes better use of SEEK_DATA/SEEK_HOLE in cachefiles_read_or_alloc_pages() by caching data/hole information to use on the subsequent pages in the list.
Note that the pages list needs to be transited in reverse for this to work as it seems that the list passed to the fs is reverse-sorted.
What I see in the kernel output when reading a 16MB file is:
[cat ] ==> cachefiles_read_or_alloc_pages({OBJ5,1},,512,,)
[cat ] SEEK_DATA: 0
[cat ] SEEK_HOLE: 1000000
[cat ] <== cachefiles_read_or_alloc_pages() = 0 [nr=0 empty]
[cat ] ==> cachefiles_read_or_alloc_pages({OBJ5,1},,512,,)
[cat ] SEEK_DATA: 200000
[cat ] SEEK_HOLE: 1000000
[cat ] <== cachefiles_read_or_alloc_pages() = 0 [nr=0 empty]
[cat ] ==> cachefiles_read_or_alloc_pages({OBJ5,1},,512,,)
[cat ] SEEK_DATA: 400000
[cat ] SEEK_HOLE: 1000000
[cat ] <== cachefiles_read_or_alloc_pages() = 0 [nr=0 empty]
[cat ] ==> cachefiles_read_or_alloc_pages({OBJ5,1},,512,,)
[cat ] SEEK_DATA: 600000
[cat ] SEEK_HOLE: 1000000
[cat ] <== cachefiles_read_or_alloc_pages() = 0 [nr=0 empty]
[cat ] ==> cachefiles_read_or_alloc_pages({OBJ5,1},,512,,)
[cat ] SEEK_DATA: 800000
[cat ] SEEK_HOLE: 1000000
[cat ] <== cachefiles_read_or_alloc_pages() = 0 [nr=0 empty]
[cat ] ==> cachefiles_read_or_alloc_pages({OBJ5,1},,512,,)
[cat ] SEEK_DATA: a00000
[cat ] SEEK_HOLE: 1000000
[cat ] <== cachefiles_read_or_alloc_pages() = 0 [nr=0 empty]
[cat ] ==> cachefiles_read_or_alloc_pages({OBJ5,1},,512,,)
[cat ] SEEK_DATA: c00000
[cat ] SEEK_HOLE: 1000000
[cat ] <== cachefiles_read_or_alloc_pages() = 0 [nr=0 empty]
[cat ] ==> cachefiles_read_or_alloc_pages({OBJ5,1},,512,,)
[cat ] SEEK_DATA: e00000
[cat ] SEEK_HOLE: 1000000
[cat ] <== cachefiles_read_or_alloc_pages() = 0 [nr=0 empty]
[cat ] ==> cachefiles_read_or_alloc_page({ffff880037ffac00},{1000},,,)
[cat ] <== cachefiles_read_or_alloc_page() = -61It doesn't quite work, though - after invalidating the file, I see lots of:
[cat ] SEEK_DATA: fffffffffffffffa
That is ENXIO. I'm not sure what that portends yet.
David
---
fs/cachefiles/bind.c +2 -1
@@ -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 ;
fs/cachefiles/rdwr.c +36 -43
134 lines not on this page · raw message
fs/ext4/super.c +1 -1
@@ -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" );
PATCH 3/3 btrfs: set FS_SUPPORTS_SEEK_HOLE flag.
In reply to NeilBrownThis allows fscache to cachefiles in a btrfs filesystem.
--- fs/btrfs/super.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
fs/btrfs/super.c +2 -1
@@ -1904,7 +1904,8 @@ static struct file_system_type btrfs_fs_type = { .name = "btrfs", .mount = btrfs_mount, .kill_sb = btrfs_kill_super, - .fs_flags = FS_REQUIRES_DEV | FS_BINARY_MOUNTDATA, + .fs_flags = FS_REQUIRES_DEV | FS_BINARY_MOUNTDATA | + FS_SUPPORTS_SEEK_HOLE, };MODULE_ALIAS_FS ("btrfs" );
David Howells
maintainerRe: [PATCH 3/3] btrfs: set FS_SUPPORTS_SEEK_HOLE flag.
fs/btrfs/super.c static struct file_system_type btrfs_fs_type = { · line 1908
Quoted 2 lines · NeilBrown
fs/btrfs/super.c +2
-0+ .fs_flags = FS_REQUIRES_DEV | FS_BINARY_MOUNTDATA | + FS_SUPPORTS_SEEK_HOLE,
I must be missing something:
warthog>git merge linus/master Already up-to-date.
warthog>stg id 09d51602cf84a1264946711dd4ea0dddbac599a1 warthog>grep -r FS_SUPPORTS_SEEK_HOLE include/ warthog1>git grep FS_SUPPORTS_SEEK_HOLE warthog1>
David
Re: [PATCH 3/3] btrfs: set FS_SUPPORTS_SEEK_HOLE flag.
Quoted 7 lines · On Mon, 20 Apr 2015 09:47:42 +0100 David Howells <[email protected]> wrote:
fs/btrfs/super.c static struct file_system_type btrfs_fs_type = { · line 1908
Quoted 2 lines · NeilBrown
fs/btrfs/super.c +2
-0+ .fs_flags = FS_REQUIRES_DEV | FS_BINARY_MOUNTDATA | + FS_SUPPORTS_SEEK_HOLE,I must be missing something:
Quoted 8 lines
warthog>git merge linus/master Already up-to-date.
warthog>stg id09d51602cf84a1264946711dd4ea0dddbac599a1warthog>grep -rFS_SUPPORTS_SEEK_HOLEinclude/warthog1>git grepFS_SUPPORTS_SEEK_HOLEwarthog1>
Missing patch 2 of the 3-patch series?
NeilBrown
David Howells
maintainerRe: [PATCH 3/3] btrfs: set FS_SUPPORTS_SEEK_HOLE flag.
Quoted 1 line · NeilBrown
Missing patch 2 of the 3-patch series?
Yes. :-)
Do ext4 and xfs support this, do you know?
David
Re: [PATCH 3/3] btrfs: set FS_SUPPORTS_SEEK_HOLE flag.
Quoted 7 lines · David Howells
Quoted 1 line · NeilBrown
Missing patch 2 of the 3-patch series?
Yes. :-)
Do ext4 and xfs support this, do you know?
Yes. As do f2fs, ocfs2, gfs2, ceph and NFSv4.2
Quoted 2 lines
David
---end quoted text---
Al Viro
maintainerRe: [PATCH 3/3] btrfs: set FS_SUPPORTS_SEEK_HOLE flag.
Quoted 10 lines · Christoph Hellwig
Quoted 7 lines · David Howells
Quoted 1 line · NeilBrown
Missing patch 2 of the 3-patch series?
Yes. :-)
Do ext4 and xfs support this, do you know?
Yes. As do f2fs, ocfs2, gfs2, ceph and NFSv4.2
Er... Nominally, gfs2 supports it. By treating all files as "there's a hole starting at EOF". Same as ext2 or even minix...
Re: [PATCH 3/3] btrfs: set FS_SUPPORTS_SEEK_HOLE flag.
Quoted 6 lines · Al Viro
Quoted 3 lines
Quoted 1 line
Do ext4 and xfs support this, do you know?
Yes. As do f2fs, ocfs2, gfs2, ceph and NFSv4.2
Er... Nominally, gfs2 supports it. By treating all files as "there's a hole starting at EOF". Same as ext2 or even minix...
Yeah remove gfs2 from the list.
Re: [PATCH 3/3] btrfs: set FS_SUPPORTS_SEEK_HOLE flag.
Quoted 9 lines · Christoph Hellwig
Quoted 6 lines · Al Viro
Quoted 3 lines
Quoted 1 line
Do ext4 and xfs support this, do you know?
Yes. As do f2fs, ocfs2, gfs2, ceph and NFSv4.2
Er... Nominally, gfs2 supports it. By treating all files as "there's a hole starting at EOF". Same as ext2 or even minix...
Yeah remove gfs2 from the list.
But please add tmpfs to the list -
though I doubt you're interested in caching its files.
Hugh
Re: [PATCH 3/3] btrfs: set FS_SUPPORTS_SEEK_HOLE flag.
In reply to Christoph HellwigQuoted 10 lines · On Mon, 20 Apr 2015 02:48:55 -0700 Christoph Hellwig <[email protected]> wrote:
Quoted 7 lines · David Howells
Quoted 1 line · NeilBrown
Missing patch 2 of the 3-patch series?
Yes. :-)
Do ext4 and xfs support this, do you know?
Yes. As do f2fs, ocfs2, gfs2, ceph and NFSv4.2
Are you sure about NFSv4.2?
I see that it *can* report holes, but is there any guarantee that if you create a new file and write only the 5th block, then READ_PLUS will reliably report that the first 4 block are holes??
Because if it doesn't guarantee that, then NFSv4.2 doesn't fit the with the others where SEEK_HOLE reliable reports holes.
On the other hand if NFSv4.2 *does* guarantee that then the current READ_PLUS server patches are broken because they just use vfs_llseek and assume that trust what it says.
It would be really nice if SEEK_{DATA,HOLE} either reported holes reliably or returned ENXIO, but I guess there was a goo reason not to do that.
Thanks,
NeilBrown
Re: [PATCH 3/3] btrfs: set FS_SUPPORTS_SEEK_HOLE flag.
Quoted 5 lines · NeilBrown
Are you sure about NFSv4.2?
I see that it *can* report holes, but is there any guarantee that if you create a new file and write only the 5th block, then
READ_PLUSwill reliably report that the first 4 block are holes??
FYI, I'm talking about SEEK here, not READ_PLUS but the issue is the same.
Quoted 5 lines
Because if it doesn't guarantee that, then NFSv4.2 doesn't fit the with the others where
SEEK_HOLEreliable reports holes.
On the other hand if NFSv4.2 *does* guarantee that then the currentREAD_PLUSserver patches are broken because they just usevfs_llseekand assume that trust what it says.
There is no quality of implementation guarantee in NFS, just like there isn't any in Linux. It's very hard to have any hard guarantees without leaking specific implementation details like a block size.
Quoted 2 lines
It would be really nice if SEEK_{DATA,HOLE} either reported holes reliably or returned ENXIO, but I guess there was a goo reason not to do that.
It would hav been useful, but we went with the Solaris way of reporting a giant hole. Solaris at least has a pathconf value telling you if real SEEK_{DATA,HOLE} are supported, but with Linus' hatred of that syscall we only have a bad emulation in glibc that isn't of much help here.
Re: [PATCH 3/3] btrfs: set FS_SUPPORTS_SEEK_HOLE flag.
In reply to NeilBrownQuoted 1 line · NeilBrown
This allows fscache to cachefiles in a btrfs filesystem.
Thanks for working on this Neil.
-chris
Quoted 22 lines
Signed-off-by NeilBrown <[email protected]>--- fs/btrfs/super.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)fs/btrfs/super.c +2
-1@@ -1904,7 +1904,8 @@ static struct file_system_type btrfs_fs_type = { .name = "btrfs", .mount = btrfs_mount, .kill_sb = btrfs_kill_super, - .fs_flags = FS_REQUIRES_DEV | FS_BINARY_MOUNTDATA, + .fs_flags = FS_REQUIRES_DEV | FS_BINARY_MOUNTDATA | + FS_SUPPORTS_SEEK_HOLE, };MODULE_ALIAS_FS ("btrfs" );