hi,
 fscache cannot currently be used with btrfs as the backing store for the
 cache (managed by cachefilesd).
 This is because cachefiles needs the ->bmap address_space_operation, and
 btrfs doesn't provide it.

 cachefiles only uses this to find out if a particular page is a 'hole' or
 not.  For btrfs, this can be done with 'SEEK_DATA'.

 Unfortunately it doesn't seem to be possible to query a filesystem or a file
 to see if SEEK_DATA is reliable or not, so we cannot simply use SEEK_DATA
 when reliable, else ->bmap if available.

 The following patch make fscache work for me on btrfs.  It explicitly checks
 for BTRFS_SUPER_MAGIC.  Not really a nice solution, but all I could think of.

 Is there a better way?  Could a better way be created?  Maybe
 SEEK_DATA_RELIABLE ??

 Comments, suggestions welcome.


Also, if you do try to use fscache on btrfs with 3.19, then nothing gets
cached (as expected) and with a heavy load you can lose a race and get an
asserting fail in fscache_enqueue_operation

        ASSERT(fscache_object_is_available(op->object));

It looks like the object is being killed before it is available...

[  859.700765] kernel BUG at ../fs/fscache/operation.c:38!
...
[  859.703124] Call Trace:
[  859.703193]  [<ffffffffa0448044>] fscache_run_op.isra.4+0x34/0x80 [fscache]
[  859.703260]  [<ffffffffa0448160>] fscache_start_operations+0xa0/0xf0 
[fscache]
[  859.703388]  [<ffffffffa0446cd8>] fscache_kill_object+0x98/0xc0 [fscache]
[  859.703455]  [<ffffffffa04475c1>] fscache_object_work_func+0x151/0x210 
[fscache]
[  859.703578]  [<ffffffff81078b07>] process_one_work+0x147/0x3c0
[  859.703642]  [<ffffffff8107929c>] worker_thread+0x20c/0x470

I haven't figured out the cause of that yet.


Thanks,
NeilBrown




diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c
index 1e51714eb33e..1389d8483d5d 100644
--- a/fs/cachefiles/namei.c
+++ b/fs/cachefiles/namei.c
@@ -20,6 +20,7 @@
 #include <linux/namei.h>
 #include <linux/security.h>
 #include <linux/slab.h>
+#include <linux/magic.h>
 #include "internal.h"
 
 #define CACHEFILES_KEYBUF_SIZE 512
@@ -647,7 +648,8 @@ lookup_again:
 
                        ret = -EPERM;
                        aops = object->dentry->d_inode->i_mapping->a_ops;
-                       if (!aops->bmap)
+                       if (!aops->bmap &&
+                           object->dentry->d_sb->s_magic != BTRFS_SUPER_MAGIC)
                                goto check_error;
 
                        object->backer = object->dentry;
diff --git a/fs/cachefiles/rdwr.c b/fs/cachefiles/rdwr.c
index c6cd8d7a4eef..49fb330c0ab8 100644
--- a/fs/cachefiles/rdwr.c
+++ b/fs/cachefiles/rdwr.c
@@ -410,11 +410,11 @@ int cachefiles_read_or_alloc_page(struct 
fscache_retrieval *op,
 
        inode = object->backer->d_inode;
        ASSERT(S_ISREG(inode->i_mode));
-       ASSERT(inode->i_mapping->a_ops->bmap);
        ASSERT(inode->i_mapping->a_ops->readpages);
 
        /* calculate the shift required to use bmap */
-       if (inode->i_sb->s_blocksize > PAGE_SIZE)
+       if (inode->i_mapping->a_ops->bmap &&
+           inode->i_sb->s_blocksize > PAGE_SIZE)
                goto enobufs;
 
        shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits;
@@ -423,20 +423,36 @@ int cachefiles_read_or_alloc_page(struct 
fscache_retrieval *op,
        op->op.flags |= FSCACHE_OP_ASYNC;
        op->op.processor = cachefiles_read_copier;
 
-       /* 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
-        */
-       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);
+       if (inode->i_mapping->a_ops->bmap) {
+               /* 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
+                */
+               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);
+       } else {
+               /* Use llseek */
+               struct path path;
+               struct file *file;
+               path.mnt = cache->mnt;
+               path.dentry = object->backer;
+               file = dentry_open(&path, O_RDONLY, cache->cache_cred);
+               if (IS_ERR(file))
+                       goto enobufs;
+               block = vfs_llseek(file, page->index << PAGE_SHIFT, SEEK_DATA);
+               filp_close(file, NULL);
+               if (block != page->index << PAGE_SHIFT)
+                       block = 0;
+               else
+                       block = 1;
+       }
        if (block) {
                /* submit the apparently valid page to the backing fs to be
                 * read from disk */
@@ -707,11 +723,11 @@ int cachefiles_read_or_alloc_pages(struct 
fscache_retrieval *op,
 
        inode = object->backer->d_inode;
        ASSERT(S_ISREG(inode->i_mode));
-       ASSERT(inode->i_mapping->a_ops->bmap);
        ASSERT(inode->i_mapping->a_ops->readpages);
 
        /* calculate the shift required to use bmap */
-       if (inode->i_sb->s_blocksize > PAGE_SIZE)
+       if (inode->i_mapping->a_ops->bmap &&
+           inode->i_sb->s_blocksize > PAGE_SIZE)
                goto all_enobufs;
 
        shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits;
@@ -729,21 +745,38 @@ int cachefiles_read_or_alloc_pages(struct 
fscache_retrieval *op,
        list_for_each_entry_safe(page, _n, pages, lru) {
                sector_t block0, block;
 
-               /* 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
-                */
-               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);
+               if (inode->i_mapping->a_ops->bmap) {
+                       /* 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
+                        */
+                       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);
 
+               } else {
+                       /* Use llseek */
+                       struct path path;
+                       struct file *file;
+                       path.mnt = cache->mnt;
+                       path.dentry = object->backer;
+                       file = dentry_open(&path, O_RDONLY, cache->cache_cred);
+                       if (IS_ERR(file))
+                               goto all_enobufs;
+                       block = vfs_llseek(file, page->index << PAGE_SHIFT, 
SEEK_DATA);
+                       filp_close(file, NULL);
+                       if (block != page->index << PAGE_SHIFT)
+                               block = 0;
+                       else
+                               block = 1;
+               }
                if (block) {
                        /* we have data - add it to the list to give to the
                         * backing fs */

Attachment: pgpI308DtMwLS.pgp
Description: OpenPGP digital signature

Reply via email to