From patchwork Thu Apr 9 07:49:16 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: NeilBrown X-Patchwork-Id: 6183961 Return-Path: X-Original-To: patchwork-linux-fsdevel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 99E32BF4A6 for ; Thu, 9 Apr 2015 07:49:30 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id BC5E7203E3 for ; Thu, 9 Apr 2015 07:49:29 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 9E3A6203B7 for ; Thu, 9 Apr 2015 07:49:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751630AbbDIHt0 (ORCPT ); Thu, 9 Apr 2015 03:49:26 -0400 Received: from cantor2.suse.de ([195.135.220.15]:54817 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751537AbbDIHtZ (ORCPT ); Thu, 9 Apr 2015 03:49:25 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (charybdis-ext.suse.de [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 4A5A8AAC9; Thu, 9 Apr 2015 07:49:23 +0000 (UTC) Date: Thu, 9 Apr 2015 17:49:16 +1000 From: NeilBrown To: David Howells Cc: linux-btrfs@vger.kernel.org, linux-cachefs@redhat.com, linux-fsdevel@vger.kernel.org Subject: [PATCH/RFC] fscache/cachefiles versus btrfs Message-ID: <20150409174916.5a2efef5@notabene.brown> X-Mailer: Claws Mail 3.10.1-162-g4d0ed6 (GTK+ 2.24.25; x86_64-suse-linux-gnu) MIME-Version: 1.0 Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, T_TVD_MIME_EPI, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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] [] fscache_run_op.isra.4+0x34/0x80 [fscache] [ 859.703260] [] fscache_start_operations+0xa0/0xf0 [fscache] [ 859.703388] [] fscache_kill_object+0x98/0xc0 [fscache] [ 859.703455] [] fscache_object_work_func+0x151/0x210 [fscache] [ 859.703578] [] process_one_work+0x147/0x3c0 [ 859.703642] [] 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 #include #include +#include #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 */