From patchwork Mon Sep 2 18:17:51 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Trond Myklebust X-Patchwork-Id: 2852938 Return-Path: X-Original-To: patchwork-linux-nfs@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id DF778C0AB5 for ; Mon, 2 Sep 2013 18:17:59 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id F3ADD202D1 for ; Mon, 2 Sep 2013 18:17:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 012D7202C6 for ; Mon, 2 Sep 2013 18:17:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756183Ab3IBSR5 (ORCPT ); Mon, 2 Sep 2013 14:17:57 -0400 Received: from mx1.netapp.com ([216.240.18.38]:24296 "EHLO mx1.netapp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755681Ab3IBSR4 (ORCPT ); Mon, 2 Sep 2013 14:17:56 -0400 X-IronPort-AV: E=Sophos;i="4.89,1008,1367996400"; d="scan'208";a="276840744" Received: from vmwexceht03-prd.hq.netapp.com ([10.106.76.241]) by mx1-out.netapp.com with ESMTP; 02 Sep 2013 11:17:56 -0700 Received: from smtp1.corp.netapp.com (10.57.156.124) by VMWEXCEHT03-PRD.hq.netapp.com (10.106.76.241) with Microsoft SMTP Server id 14.3.123.3; Mon, 2 Sep 2013 11:17:55 -0700 Received: from leira.trondhjem.org.com (leira.trondhjem.org.vpn.netapp.com [10.55.73.213]) by smtp1.corp.netapp.com (8.13.1/8.13.1/NTAP-1.6) with ESMTP id r82IHt6f006652; Mon, 2 Sep 2013 11:17:55 -0700 (PDT) From: Trond Myklebust To: CC: Subject: [PATCH v2] NFS: Ensure that rmdir() waits for sillyrenames to complete Date: Mon, 2 Sep 2013 14:17:51 -0400 Message-ID: <1378145871-30071-1-git-send-email-Trond.Myklebust@netapp.com> X-Mailer: git-send-email 1.8.3.1 MIME-Version: 1.0 Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org X-Spam-Status: No, score=-9.3 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, 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 If an NFS client does mkdir("dir"); fd = open("dir/file"); unlink("dir/file"); close(fd); rmdir("dir"); then the asynchronous nature of the sillyrename operation means that we can end up getting EBUSY for the rmdir() in the above test. Fix that by ensuring that we wait for any in-progress sillyrenames before sending the rmdir() to the server. Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 19 +++++++++++++------ fs/nfs/unlink.c | 7 +++++++ include/linux/nfs_fs.h | 1 + 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index d8149e9..187caa4 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1694,12 +1694,19 @@ int nfs_rmdir(struct inode *dir, struct dentry *dentry) dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); trace_nfs_rmdir_enter(dir, dentry); - error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name); - /* Ensure the VFS deletes this inode */ - if (error == 0 && dentry->d_inode != NULL) - clear_nlink(dentry->d_inode); - else if (error == -ENOENT) - nfs_dentry_handle_enoent(dentry); + if (dentry->d_inode) { + nfs_wait_on_sillyrename(dentry); + error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name); + /* Ensure the VFS deletes this inode */ + switch (error) { + case 0: + clear_nlink(dentry->d_inode); + break; + case -ENOENT: + nfs_dentry_handle_enoent(dentry); + } + } else + error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name); trace_nfs_rmdir_exit(dir, dentry, error); return error; diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 2c1485d..0c6dfe0 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c @@ -207,6 +207,13 @@ out_free: return ret; } +void nfs_wait_on_sillyrename(struct dentry *dentry) +{ + struct nfs_inode *nfsi = NFS_I(dentry->d_inode); + + wait_event(nfsi->waitqueue, atomic_read(&nfsi->silly_count) == 1); +} + void nfs_block_sillyrename(struct dentry *dentry) { struct nfs_inode *nfsi = NFS_I(dentry->d_inode); diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 7125cef..3ea4cde 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -524,6 +524,7 @@ static inline void nfs4_label_free(void *label) {} * linux/fs/nfs/unlink.c */ extern void nfs_complete_unlink(struct dentry *dentry, struct inode *); +extern void nfs_wait_on_sillyrename(struct dentry *dentry); extern void nfs_block_sillyrename(struct dentry *dentry); extern void nfs_unblock_sillyrename(struct dentry *dentry); extern int nfs_sillyrename(struct inode *dir, struct dentry *dentry);