From patchwork Mon Jan 19 09:15:11 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peng Tao X-Patchwork-Id: 5655741 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.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id BBC23C058D for ; Mon, 19 Jan 2015 09:15:35 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 950BA20306 for ; Mon, 19 Jan 2015 09:15:34 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 9B7D32028D for ; Mon, 19 Jan 2015 09:15:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751444AbbASJPc (ORCPT ); Mon, 19 Jan 2015 04:15:32 -0500 Received: from mail-pa0-f45.google.com ([209.85.220.45]:37921 "EHLO mail-pa0-f45.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751356AbbASJPb (ORCPT ); Mon, 19 Jan 2015 04:15:31 -0500 Received: by mail-pa0-f45.google.com with SMTP id lf10so37694091pab.4 for ; Mon, 19 Jan 2015 01:15:31 -0800 (PST) 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; bh=vesNDXO9A7ojlvrcloW4l+9n9f4mcjdWBg2WlvAJst4=; b=NyRgDLX6aQ2i6zHyX0XpLQLZidq40ryuMp6R2/CVW8W9otpA07X2551SqkDX6dZjiO ZbJrYvFVwG5nvL3tJyMIiKgsBciedBD3d+cSNpZagejKnxiWsscCnzgJflU1xszkFFE7 LBGIsleYMRUKcJBPk4YmF40SYMj8SIB+unjMGfzQoAxRtqANCsbLPTtoKZTy7P14307Q EtVkqfE9F6/fsO/us3P79i/YuVm2JzCgZ4k0WmwaOtpKmixeVeWxT6WYpiJht+6mb7p+ qzmDehJia8Rhk5aD0jXRAZ60vUkUBFdafeCenjqzeqZe9m2DYNEpiRk30jA4CsmA4gJo q1Ng== X-Gm-Message-State: ALoCoQnh5BwU4WH+m4Y+tKrgLjgR20Gi82qh94XmveEvQWmfbKTl9ArLb12cQ7YBwsf57/8M/BQ3 X-Received: by 10.68.135.168 with SMTP id pt8mr42931487pbb.150.1421658930902; Mon, 19 Jan 2015 01:15:30 -0800 (PST) Received: from localhost.localdomain (ec2-54-65-164-9.ap-northeast-1.compute.amazonaws.com. [54.65.164.9]) by mx.google.com with ESMTPSA id ns6sm11046172pbb.77.2015.01.19.01.15.28 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 19 Jan 2015 01:15:30 -0800 (PST) From: Peng Tao To: linux-nfs@vger.kernel.org Cc: Christoph Hellwig , Trond Myklebust , Peng Tao Subject: [PATCH v2] nfs: fix dio deadlock when O_DIRECT flag is flipped Date: Mon, 19 Jan 2015 17:15:11 +0800 Message-Id: <1421658911-18671-1-git-send-email-tao.peng@primarydata.com> X-Mailer: git-send-email 1.9.1 Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham 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 Running xfstest generic/036, we hit VM_BUG_ON() in nfs_direct_IO(). 036 toggles O_DIRECT flag while IO is going on. We cannot simply remove the VM_BUG_ON() there because we'll have a deadlock in the code path. inode->i_mutex is taken when calling into ->direct_IO. And nfs_file_direct_write() would grab inode->i_mutex again. nfs_file_write() and generic_file_write_iter() checks for O_DIRECT twice, and it creates a race window if user space is playing with O_DIRECT flag. Fix it by calling generic_perform_write() instead, so that nfs_direct_IO() is only invoked in swap on nfs case. Suggested-by: Christoph Hellwig Signed-off-by: Peng Tao --- fs/nfs/file.c | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 2ab6f00..e98604a 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -662,6 +662,45 @@ static int nfs_need_sync_write(struct file *filp, struct inode *inode) return 0; } +static ssize_t nfs_file_buffer_write(struct kiocb *iocb, struct iov_iter *from) +{ + struct file *file = iocb->ki_filp; + struct address_space *mapping = file->f_mapping; + struct inode *inode = mapping->host; + ssize_t result = 0; + size_t count = iov_iter_count(from); + loff_t pos = iocb->ki_pos; + int ret; + + mutex_lock(&inode->i_mutex); + /* We can write back this queue in page reclaim */ + current->backing_dev_info = mapping->backing_dev_info; + ret = generic_write_checks(file, &pos, &count, 0); + if (ret) + goto out; + + if (!count) + goto out; + + iov_iter_truncate(from, count); + ret = file_remove_suid(file); + if (ret) + goto out; + + ret = file_update_time(file); + if (ret) + goto out; + + result = generic_perform_write(file, from, pos); + if (likely(result >= 0)) + iocb->ki_pos = pos + result; + +out: + current->backing_dev_info = NULL; + mutex_unlock(&inode->i_mutex); + return result ? result : ret; +} + ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; @@ -697,7 +736,7 @@ ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from) if (!count) goto out; - result = generic_file_write_iter(iocb, from); + result = nfs_file_buffer_write(iocb, from); if (result > 0) written = result;