All of lore.kernel.org
 help / color / mirror / Atom feed
From: Peng Tao <tao.peng@primarydata.com>
To: linux-nfs@vger.kernel.org
Cc: Christoph Hellwig <hch@infradead.org>,
	Trond Myklebust <trond.myklebust@primarydata.com>,
	Peng Tao <tao.peng@primarydata.com>
Subject: [PATCH v2] nfs: fix dio deadlock when O_DIRECT flag is flipped
Date: Mon, 19 Jan 2015 17:15:11 +0800	[thread overview]
Message-ID: <1421658911-18671-1-git-send-email-tao.peng@primarydata.com> (raw)

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 <hch@infradead.org>
Signed-off-by: Peng Tao <tao.peng@primarydata.com>
---
 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;
 
-- 
1.9.1


             reply	other threads:[~2015-01-19  9:15 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-01-19  9:15 Peng Tao [this message]
2015-01-19 13:17 ` [PATCH v2] nfs: fix dio deadlock when O_DIRECT flag is flipped Trond Myklebust
2015-01-20  0:32   ` Peng Tao

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1421658911-18671-1-git-send-email-tao.peng@primarydata.com \
    --to=tao.peng@primarydata.com \
    --cc=hch@infradead.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=trond.myklebust@primarydata.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.