From 4960810b94d808965cae9258fb4f7583618a75e9 Mon Sep 17 00:00:00 2001 From: Andrew Perepechko Date: Thu, 11 Nov 2010 16:47:30 +0300 Subject: [PATCH] b=18233 fix read+truncate livelock The race fix for ll_readpage which creates new (just truncated) pages and truncate which truncates these pages. i=Vitaly Fertman i=Mike Pershin --- lustre/llite/file.c | 4 ++++ lustre/llite/llite_internal.h | 2 +- lustre/llite/llite_lib.c | 6 +++--- lustre/tests/sanity.sh | 17 +++++++++++++++++ 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/lustre/llite/file.c b/lustre/llite/file.c index 05daf03..7107e81 100644 --- a/lustre/llite/file.c +++ b/lustre/llite/file.c @@ -859,6 +859,8 @@ static ssize_t ll_file_io_generic(const struct lu_env *env, if(cfs_down_interruptible(&lli->lli_write_sem)) GOTO(out, result = -ERESTARTSYS); write_sem_locked = 1; + } else if (iot == CIT_READ) { + cfs_down_read(&lli->lli_trunc_sem); } break; case IO_SENDFILE: @@ -876,6 +878,8 @@ static ssize_t ll_file_io_generic(const struct lu_env *env, result = cl_io_loop(env, io); if (write_sem_locked) cfs_up(&lli->lli_write_sem); + else if (args->via_io_subtype == IO_NORMAL && iot == CIT_READ) + cfs_up_read(&lli->lli_trunc_sem); } else { /* cl_io_rw_init() handled IO */ result = io->ci_result; diff --git a/lustre/llite/llite_internal.h b/lustre/llite/llite_internal.h index 9ca31dc..f5d36c5 100644 --- a/lustre/llite/llite_internal.h +++ b/lustre/llite/llite_internal.h @@ -121,7 +121,7 @@ struct ll_inode_info { cfs_semaphore_t lli_size_sem; /* protect open and change size */ void *lli_size_sem_owner; cfs_semaphore_t lli_write_sem; - cfs_semaphore_t lli_trunc_sem; + cfs_rw_semaphore_t lli_trunc_sem; char *lli_symlink_name; __u64 lli_maxbytes; __u64 lli_ioepoch; diff --git a/lustre/llite/llite_lib.c b/lustre/llite/llite_lib.c index c3e66ba..73170fc 100644 --- a/lustre/llite/llite_lib.c +++ b/lustre/llite/llite_lib.c @@ -798,7 +798,7 @@ void ll_lli_init(struct ll_inode_info *lli) lli->lli_inode_magic = LLI_INODE_MAGIC; cfs_sema_init(&lli->lli_size_sem, 1); cfs_sema_init(&lli->lli_write_sem, 1); - cfs_sema_init(&lli->lli_trunc_sem, 1); + cfs_init_rwsem(&lli->lli_trunc_sem); lli->lli_flags = 0; lli->lli_maxbytes = PAGE_CACHE_MAXBYTES; cfs_spin_lock_init(&lli->lli_lock); @@ -1270,7 +1270,7 @@ int ll_setattr_raw(struct inode *inode, struct iattr *attr) UNLOCK_INODE_MUTEX(inode); if (ia_valid & ATTR_SIZE) UP_WRITE_I_ALLOC_SEM(inode); - cfs_down(&lli->lli_trunc_sem); + cfs_down_write(&lli->lli_trunc_sem); LOCK_INODE_MUTEX(inode); if (ia_valid & ATTR_SIZE) DOWN_WRITE_I_ALLOC_SEM(inode); @@ -1311,7 +1311,7 @@ out: rc1 = ll_setattr_done_writing(inode, op_data, mod); ll_finish_md_op_data(op_data); } - cfs_up(&lli->lli_trunc_sem); + cfs_up_write(&lli->lli_trunc_sem); return rc ? rc : rc1; } diff --git a/lustre/tests/sanity.sh b/lustre/tests/sanity.sh index ae7e8e9..18ee710 100755 --- a/lustre/tests/sanity.sh +++ b/lustre/tests/sanity.sh @@ -7706,6 +7706,23 @@ test_217() { # bug 22430 } run_test 217 "check lctl ping for hostnames with hiphen ('-')" +test_218() { + # do directio so as not to populate the page cache + log "creating a 10 Mb file" + multiop $DIR/$tfile oO_CREAT:O_DIRECT:O_RDWR:w$((10*1048576))c || error "multiop failed while creating a file" + log "starting reads" + dd if=$DIR/$tfile of=/dev/null bs=4096 & + log "truncating the file" + multiop $DIR/$tfile oO_TRUNC:c || error "multiop failed while truncating the file" + log "killing dd" + kill %+ || true # reads might have finished + echo "wait until dd is finished" + wait + log "removing the temporary file" + rm -rf $DIR/$tfile || error "tmp file removal failed" +} +run_test 218 "parallel read and truncate should not deadlock =======================" + # # tests that do cleanup/setup should be run at the end # -- 1.8.3.1