From patchwork Fri Sep 28 15:42:31 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miklos Szeredi X-Patchwork-Id: 10620129 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 0ED6915A6 for ; Fri, 28 Sep 2018 15:43:27 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 04F8C2868D for ; Fri, 28 Sep 2018 15:43:27 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0310E28C6E; Fri, 28 Sep 2018 15:43:26 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 88A4528AFC for ; Fri, 28 Sep 2018 15:43:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729493AbeI1WHo (ORCPT ); Fri, 28 Sep 2018 18:07:44 -0400 Received: from mail-wm1-f66.google.com ([209.85.128.66]:39754 "EHLO mail-wm1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729475AbeI1WHJ (ORCPT ); Fri, 28 Sep 2018 18:07:09 -0400 Received: by mail-wm1-f66.google.com with SMTP id q8-v6so2676757wmq.4 for ; Fri, 28 Sep 2018 08:42:48 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=VHkYwroxtfKl4m4UAHETv8/4pMVos/KNrqgWkjWkSTA=; b=W16K2dX9urT9Qc1Pq8Yi5cOS5LhOcogkqkUIHfdHjwOAFsa37l8VTCq2nJ4Ah76XhQ yhBGskALiiEk6t+fyoAGwdj90gaTXqEm/a7lO149+dH+aCA/v9ydIvGZTX5CdST4MIsb aoYoKuSLcIqcQVHdZ1Jw8LmRffHbOo/C0cZVyE4mQqwMeTfgHEWdLZoS5YJQ3Wg7HALH IsnvUAq2KzFyACi5eHpIQfIQ/Sdn0rjyI5a9GTe9k9Mre6CJCUCRBT4KjBD2DhySzVbP NZVHg/X5pSv+DUrCNSf1RnCeUeHy30o2aqbPbr5418My97nSCsvlgaCTAERmSWH4QWq0 fNRw== X-Gm-Message-State: ABuFfoiM+qKcPMUIUQpPUd5WUAnR9bH+vuJl80Y9XrsmpUCfig3/ZB8J bgwUaOpxNbaTYS9z7hsSNxiW0Afyhao= X-Google-Smtp-Source: ACcGV61qr7SWPN47A9E4txgU070HQIoZS3imfYaFC3W6wijbRfdbjWKiIeData0DglUy5kpKJQm3sA== X-Received: by 2002:a1c:b90c:: with SMTP id j12-v6mr2367777wmf.32.1538149367789; Fri, 28 Sep 2018 08:42:47 -0700 (PDT) Received: from veci.piliscsaba.redhat.com (catv-212-96-48-140.catv.broadband.hu. [212.96.48.140]) by smtp.gmail.com with ESMTPSA id v2-v6sm2009877wme.36.2018.09.28.08.42.46 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Fri, 28 Sep 2018 08:42:47 -0700 (PDT) From: Miklos Szeredi To: linux-fsdevel@vger.kernel.org Cc: linux-kernel@vger.kernel.org Subject: [PATCH 6/9] fuse: add readdir cache version Date: Fri, 28 Sep 2018 17:42:31 +0200 Message-Id: <20180928154234.19270-7-mszeredi@redhat.com> X-Mailer: git-send-email 2.14.3 In-Reply-To: <20180928154234.19270-1-mszeredi@redhat.com> References: <20180928154234.19270-1-mszeredi@redhat.com> Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Allow the cache to be invalidated when page(s) have gone missing. In this case increment the version of the cache and reset to an empty state. Add a version number to the directory stream in struct fuse_file as well, indicating the version of the cache it's supposed to be reading. If the cache version doesn't match the stream's version, then reset the stream to the beginning of the cache. Signed-off-by: Miklos Szeredi --- fs/fuse/fuse_i.h | 7 +++++++ fs/fuse/inode.c | 1 + fs/fuse/readdir.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 116fe14053f1..ef018ea5bcd9 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -114,6 +114,9 @@ struct fuse_inode { /** position at end of cache (position of next entry) */ loff_t pos; + /** version of the cache */ + u64 version; + /** protects above fields */ spinlock_t lock; } rdc; @@ -176,6 +179,10 @@ struct fuse_file { /** Offset in cache */ loff_t cache_off; + + /** Version of cache we are reading */ + u64 version; + } readdir; /** RB node to be linked on fuse_conn->polled_files */ diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 03d8105a851d..6d0a87308f86 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -104,6 +104,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) fi->rdc.cached = false; fi->rdc.size = 0; fi->rdc.pos = 0; + fi->rdc.version = 0; mutex_init(&fi->mutex); fi->forget = fuse_alloc_forget(); if (!fi->forget) { diff --git a/fs/fuse/readdir.c b/fs/fuse/readdir.c index e6ae82f2df9d..edb445c4cfbd 100644 --- a/fs/fuse/readdir.c +++ b/fs/fuse/readdir.c @@ -34,6 +34,7 @@ static void fuse_add_dirent_to_cache(struct file *file, pgoff_t index; struct page *page; loff_t size; + u64 version; unsigned int offset; void *addr; @@ -46,6 +47,7 @@ static void fuse_add_dirent_to_cache(struct file *file, spin_unlock(&fi->rdc.lock); return; } + version = fi->rdc.version; size = fi->rdc.size; offset = size & ~PAGE_MASK; index = size >> PAGE_SHIFT; @@ -67,7 +69,8 @@ static void fuse_add_dirent_to_cache(struct file *file, spin_lock(&fi->rdc.lock); /* Raced with another readdir */ - if (fi->rdc.size != size || WARN_ON(fi->rdc.pos != pos)) + if (fi->rdc.version != version || fi->rdc.size != size || + WARN_ON(fi->rdc.pos != pos)) goto unlock; addr = kmap_atomic(page); @@ -394,6 +397,14 @@ static enum fuse_parse_result fuse_parse_cache(struct fuse_file *ff, return res; } +static void fuse_rdc_reset(struct fuse_inode *fi) +{ + fi->rdc.cached = false; + fi->rdc.version++; + fi->rdc.size = 0; + fi->rdc.pos = 0; +} + #define UNCACHED 1 static int fuse_readdir_cached(struct file *file, struct dir_context *ctx) @@ -419,6 +430,21 @@ static int fuse_readdir_cached(struct file *file, struct dir_context *ctx) spin_unlock(&fi->rdc.lock); return UNCACHED; } + /* + * If cache version changed since the last getdents() call, then reset + * the cache stream. + */ + if (ff->readdir.version != fi->rdc.version) { + ff->readdir.pos = 0; + ff->readdir.cache_off = 0; + } + /* + * If at the beginning of the cache, than reset version to + * current. + */ + if (ff->readdir.pos == 0) + ff->readdir.version = fi->rdc.version; + WARN_ON(fi->rdc.size < ff->readdir.cache_off); index = ff->readdir.cache_off >> PAGE_SHIFT; @@ -435,13 +461,30 @@ static int fuse_readdir_cached(struct file *file, struct dir_context *ctx) page = find_get_page_flags(file->f_mapping, index, FGP_ACCESSED | FGP_LOCK); + spin_lock(&fi->rdc.lock); if (!page) { /* * Uh-oh: page gone missing, cache is useless */ + if (fi->rdc.version == ff->readdir.version) + fuse_rdc_reset(fi); + spin_unlock(&fi->rdc.lock); return UNCACHED; } + /* Make sure it's still the same version after getting the page. */ + if (ff->readdir.version != fi->rdc.version) { + spin_unlock(&fi->rdc.lock); + unlock_page(page); + put_page(page); + goto retry; + } + spin_unlock(&fi->rdc.lock); + + /* + * Contents of the page are now protected against changing by holding + * the page lock. + */ addr = kmap(page); res = fuse_parse_cache(ff, addr, size, ctx); kunmap(page);