From patchwork Tue Nov 17 11:52:52 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 7636281 Return-Path: X-Original-To: patchwork-linux-nfs@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id A43519F65E for ; Tue, 17 Nov 2015 11:54:21 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 68C28204EA for ; Tue, 17 Nov 2015 11:54:16 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 3FA61204E2 for ; Tue, 17 Nov 2015 11:54:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753615AbbKQLxy (ORCPT ); Tue, 17 Nov 2015 06:53:54 -0500 Received: from mail-qk0-f181.google.com ([209.85.220.181]:35872 "EHLO mail-qk0-f181.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753567AbbKQLxt (ORCPT ); Tue, 17 Nov 2015 06:53:49 -0500 Received: by qkda6 with SMTP id a6so1677229qkd.3 for ; Tue, 17 Nov 2015 03:53:48 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=poochiereds_net.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=7Ip9zorEm3yvZDkRoB5KA+47Jt+kMWcjGuc3IAopTjI=; b=tIXQe/B5aItl2J6QW5xbkszUCUxMeQCjOuTrPR6JttqKYtkvQu47lA9h0lVLzyy9wE RmjSI2Ht5PRp9K0UOjw9xV20DL4UrsEeKR1JJCyJ56/GF4q/2Zig3rvF8Ir/pzEzIrA/ ZhNtnYyQBBFkrftRNhP9tw/6G3jhcy6JbXQWBZJF0U3ambNpJBMd5AUUxutpIKp8/ewa BELzTxptVcsScRab0c5oTzuqR+muGBmNTl6KlxWMz5Ux8qNp1vApxhZTaTNRR8S7tNT1 3o34jsBx1DMyhx/isRWt29sD/SOBILmkx4z5j+phbt/G57BYwwwqhA3ejtQsHdHqZeeq hHDA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=7Ip9zorEm3yvZDkRoB5KA+47Jt+kMWcjGuc3IAopTjI=; b=UkM0MEQMo67GXhN5P8qlp2qg8id7+sqmKeLxv/UMWVl8A3k1U+gWhda8Nmwct4nuBw ydeD/qMZyreC66qjP7B2666DsjI9sVK4V0/TNiZJwc/xcUjHvAoKuwaHS/p9MSCulbzc HicMep0MDRiv2MfaKc5PNePz7usHFcYwi5AuJGayzrfhKudNslRSnZwVTCDCDD6qzQI6 /PDSXwYf9J6SGDRg0ucsiGgltVKTiMDl/GOCHsomOeDRes/Nug6AvR7gNy4BGYOW/des 3j89tn7f9Z92M6hnzCMDh9GBudO8DTzSMaxuVeKFucvPjyp7PgzBK/GT58XF5JUJRtyo SeZg== X-Gm-Message-State: ALoCoQnPUMwlbeoxUKu5UUrl+Wy8/PVDm7HQa3MSvmVUZVzD4sat1ESR9efIm1FhqNhcrI1DwCw7 X-Received: by 10.55.204.213 with SMTP id n82mr41362048qkl.36.1447761228434; Tue, 17 Nov 2015 03:53:48 -0800 (PST) Received: from tlielax.poochiereds.net ([2606:a000:1125:4075::d5a]) by smtp.googlemail.com with ESMTPSA id w10sm1583910qhc.16.2015.11.17.03.53.47 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 17 Nov 2015 03:53:47 -0800 (PST) From: Jeff Layton X-Google-Original-From: Jeff Layton To: bfields@fieldses.org, trond.myklebust@primarydata.com Cc: linux-nfs@vger.kernel.org, Eric Paris , Alexander Viro , linux-fsdevel@vger.kernel.org Subject: [PATCH v1 30/38] nfsd: close cached file when underlying file systems says no such file Date: Tue, 17 Nov 2015 06:52:52 -0500 Message-Id: <1447761180-4250-31-git-send-email-jeff.layton@primarydata.com> X-Mailer: git-send-email 2.4.3 In-Reply-To: <1447761180-4250-1-git-send-email-jeff.layton@primarydata.com> References: <1447761180-4250-1-git-send-email-jeff.layton@primarydata.com> Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org X-Spam-Status: No, score=-7.4 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,RP_MATCHES_RCVD,T_DKIM_INVALID,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 From: Peng Tao Upon setattr, fallocate, read, write, commit, if underlying file system returns EBADF or ENOENT, we should close the cached file. This is possible on data portal when remote files are removed by other clients. Also call .d_weak_revalidate() upon such failures and if we finds out inode is still valid, retry above operation once. In theory we should not see the retry but it makes code more robust, in case underlying nfsv4 state recovery fails badly. [jlayton: turn retry ints into bools] Signed-off-by: Peng Tao Signed-off-by: Jeff Layton --- fs/nfsd/vfs.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 83 insertions(+), 22 deletions(-) diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 5293cba6b8f8..ca6896bb25fb 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -333,6 +333,51 @@ out_nfserrno: return nfserrno(host_err); } +static void +nfsd_close_cached_files(struct dentry *dentry) +{ + struct inode *inode = d_inode(dentry); + + if (inode && S_ISREG(inode->i_mode)) + nfsd_file_close_inode_sync(inode); +} + +static bool +nfsd_has_cached_files(struct dentry *dentry) +{ + bool ret = false; + struct inode *inode = d_inode(dentry); + + if (inode && S_ISREG(inode->i_mode)) + ret = nfsd_file_is_cached(inode); + return ret; +} + +static bool +nfsd_cached_files_handle_vfs_error(struct dentry *dentry, int err) +{ + struct inode *inode = d_inode(dentry); + + switch (err) { + case -EBADF: + case -ENOENT: + case -EOPENSTALE: + if (inode && S_ISREG(inode->i_mode)) + nfsd_file_close_inode_sync(inode); + if (dentry->d_flags & DCACHE_OP_WEAK_REVALIDATE && + dentry->d_op->d_weak_revalidate(dentry, LOOKUP_REVAL) > 0) { + printk(KERN_NOTICE + "%s: file %s still alive!\n", __func__, + dentry->d_name.name); + return true; + } + default: + break; + } + + return false; +} + /* * Set various file attributes. After this call fhp needs an fh_put. */ @@ -348,12 +393,14 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, int host_err; bool get_write_count; int size_change = 0; + bool retry = false; if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE)) accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE; if (iap->ia_valid & ATTR_SIZE) ftype = S_IFREG; +try_again: /* Callers that do fh_verify should do the fh_want_write: */ get_write_count = !fhp->fh_dentry; @@ -410,6 +457,10 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, fh_lock(fhp); host_err = notify_change(dentry, iap, NULL); fh_unlock(fhp); + if (!retry && nfsd_cached_files_handle_vfs_error(dentry, host_err)) { + retry = true; + goto try_again; + } err = nfserrno(host_err); out_put_write_access: @@ -466,6 +517,7 @@ __be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp, mutex_lock(&d_inode(dentry)->i_mutex); host_error = security_inode_setsecctx(dentry, label->data, label->len); mutex_unlock(&d_inode(dentry)->i_mutex); + nfsd_cached_files_handle_vfs_error(dentry, host_error); return nfserrno(host_error); } #else @@ -489,6 +541,7 @@ __be32 nfsd4_vfs_fallocate(struct svc_rqst *rqstp, struct svc_fh *fhp, if (!error) error = commit_metadata(fhp); + nfsd_cached_files_handle_vfs_error(fhp->fh_dentry, error); return nfserrno(error); } #endif /* defined(CONFIG_NFSD_V4) */ @@ -659,7 +712,8 @@ retry: file = dentry_open(&path, flags, current_cred()); if (IS_ERR(file)) { - if (file == ERR_PTR(-EOPENSTALE) && !retried) { + if (nfsd_cached_files_handle_vfs_error(path.dentry, PTR_ERR(file)) + && !retried) { retried = true; fh_put(fhp); err = fh_verify(rqstp, fhp, type, may_flags); @@ -776,7 +830,7 @@ nfsd_finish_read(struct file *file, unsigned long *count, int host_err) *count = host_err; fsnotify_access(file); return 0; - } else + } else return nfserrno(host_err); } @@ -930,8 +984,10 @@ __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, { __be32 err; struct nfsd_file *nf; + int retry = false; trace_read_start(rqstp, fhp, offset, vlen); +try_again: err = nfsd_file_acquire(rqstp, fhp, NFSD_MAY_READ, &nf); if (err == nfs_ok) { trace_read_opened(rqstp, fhp, offset, vlen); @@ -939,6 +995,11 @@ __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, count); trace_read_io_done(rqstp, fhp, offset, vlen); nfsd_file_put(nf); + if (!retry && + nfsd_cached_files_handle_vfs_error(fhp->fh_dentry, err)) { + retry = true; + goto try_again; + } } trace_read_done(rqstp, fhp, offset, vlen); return err; @@ -955,8 +1016,10 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, { __be32 err; struct nfsd_file *nf; + bool retry = false; trace_write_start(rqstp, fhp, offset, vlen); +try_again: err = nfsd_file_acquire(rqstp, fhp, NFSD_MAY_WRITE, &nf); if (err == nfs_ok) { trace_write_opened(rqstp, fhp, offset, vlen); @@ -964,6 +1027,10 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, vlen, cnt, stablep); trace_write_io_done(rqstp, fhp, offset, vlen); nfsd_file_put(nf); + if (!retry && nfsd_cached_files_handle_vfs_error(fhp->fh_dentry, err)) { + retry = true; + goto try_again; + } } trace_write_done(rqstp, fhp, offset, vlen); return err; @@ -986,6 +1053,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf; loff_t end = LLONG_MAX; __be32 err = nfserr_inval; + bool retry = false; if (offset < 0) goto out; @@ -995,6 +1063,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, goto out; } +try_again: err = nfsd_file_acquire(rqstp, fhp, NFSD_MAY_WRITE|NFSD_MAY_NOT_BREAK_LEASE, &nf); if (err) @@ -1002,6 +1071,11 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, if (EX_ISSYNC(fhp->fh_export)) { int err2 = vfs_fsync_range(nf->nf_file, offset, end, 0); + if (!retry && nfsd_cached_files_handle_vfs_error(fhp->fh_dentry, err)) { + nfsd_file_put(nf); + retry = true; + goto try_again; + } if (err2 != -EINVAL) err = nfserrno(err2); else @@ -1471,7 +1545,9 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, struct inode *dirp; __be32 err; int host_err; + int retry = true; +try_again: err = fh_verify(rqstp, ffhp, S_IFDIR, NFSD_MAY_CREATE); if (err) goto out; @@ -1524,6 +1600,11 @@ out_dput: out_unlock: fh_unlock(ffhp); fh_drop_write(tfhp); + if (!retry && + nfsd_cached_files_handle_vfs_error(tfhp->fh_dentry, host_err)) { + retry = true; + goto try_again; + } out: return err; @@ -1532,26 +1613,6 @@ out_nfserr: goto out_unlock; } -static void -nfsd_close_cached_files(struct dentry *dentry) -{ - struct inode *inode = d_inode(dentry); - - if (inode && S_ISREG(inode->i_mode)) - nfsd_file_close_inode_sync(inode); -} - -static bool -nfsd_has_cached_files(struct dentry *dentry) -{ - bool ret = false; - struct inode *inode = d_inode(dentry); - - if (inode && S_ISREG(inode->i_mode)) - ret = nfsd_file_is_cached(inode); - return ret; -} - /* * Rename a file * N.B. After this call _both_ ffhp and tfhp need an fh_put