From 74a7b9cbb2fe1729db7bcf74fef031fed73239d7 Mon Sep 17 00:00:00 2001 From: "michael.mckay" Date: Wed, 19 Sep 2012 10:54:56 -0400 Subject: [PATCH] LU-1978 llite: Fix i_size race with truncate and mkwrite These changes address a race between the truncate process and the mkwrite process. We add an additional check in the case of a mkwrite to make sure we are not past the end of the file. While holding the lli_trunc_sem lock we check the size and make sure we are not past the end of the file. If we are we return -ENODATA which will trigger a SIGBUS. This is similar to what occurs in the ext4 filesystem in these cases. The return status to -ENODATA which will eventually get mapped to VM_FAULT_NOPAGE (ll_page_mkwrite()). The kernel will then return a SIGBUS. These changes return -ENODATA to ensure we correctly clean up. In the case of the mapping being null nothing will change. Xyratex-bug-id: MRP-651 Reviewed-by: Andrew Perepechko Reviewed-by: Alexander Zarochentsev Signed-off-by: Michael McKay Change-Id: Ice41b20ac16d81be44fb0c6a1bf0da8b2fcf9b7c Reviewed-on: http://review.whamcloud.com/4044 Reviewed-by: Jinshan Xiong Tested-by: Hudson Tested-by: Maloo Reviewed-by: Keith Mannthey Reviewed-by: Andreas Dilger --- lustre/llite/vvp_io.c | 44 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/lustre/llite/vvp_io.c b/lustre/llite/vvp_io.c index 46644c8..413fd94 100644 --- a/lustre/llite/vvp_io.c +++ b/lustre/llite/vvp_io.c @@ -713,6 +713,36 @@ static int vvp_io_fault_start(const struct lu_env *env, GOTO(out, result = +1); } + + if (fio->ft_mkwrite ) { + pgoff_t last_index; + /* + * Capture the size while holding the lli_trunc_sem from above + * we want to make sure that we complete the mkwrite action + * while holding this lock. We need to make sure that we are + * not past the end of the file. + */ + last_index = cl_index(obj, size - 1); + if (last_index < fio->ft_index) { + CDEBUG(D_PAGE, + "llite: mkwrite and truncate race happened: " + "%p: 0x%lx 0x%lx\n", + vmpage->mapping,fio->ft_index,last_index); + /* + * We need to return if we are + * passed the end of the file. This will propagate + * up the call stack to ll_page_mkwrite where + * we will return VM_FAULT_NOPAGE. Any non-negative + * value returned here will be silently + * converted to 0. If the vmpage->mapping is null + * the error code would be converted back to ENODATA + * in ll_page_mkwrite0. Thus we return -ENODATA + * to handle both cases + */ + GOTO(out, result = -ENODATA); + } + } + page = cl_page_find(env, obj, fio->ft_index, vmpage, CPT_CACHEABLE); if (IS_ERR(page)) GOTO(out, result = PTR_ERR(page)); @@ -750,11 +780,17 @@ static int vvp_io_fault_start(const struct lu_env *env, GOTO(out, result); } else cl_page_disown(env, io, page); - } - } + } + } - last = cl_index(obj, size - 1); - LASSERT(fio->ft_index <= last); + last = cl_index(obj, size - 1); + /* + * The ft_index is only used in the case of + * a mkwrite action. We need to check + * our assertions are correct, since + * we should have caught this above + */ + LASSERT(!fio->ft_mkwrite || fio->ft_index <= last); if (fio->ft_index == last) /* * Last page is mapped partially. -- 1.8.3.1