Commit 87e6cd7c authored by James Bottomley's avatar James Bottomley Committed by Ard Biesheuvel
Browse files

selftests/efivarfs: add concurrent update tests



The delete on last close functionality can now only be tested properly
by using multiple threads to hold open the variable files and testing
what happens as they complete.

Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
Signed-off-by: default avatarArd Biesheuvel <ardb@kernel.org>
parent fd3aa3d5
Loading
Loading
Loading
Loading
+134 −0
Original line number Diff line number Diff line
@@ -227,6 +227,136 @@ test_no_set_size()
	exit $ret
}

setup_test_multiple()
{
       ##
       # we're going to do multi-threaded tests, so create a set of
       # pipes for synchronization.  We use pipes 1..3 to start the
       # stalled shell job and pipes 4..6 as indicators that the job
       # has started.  If you need more than 3 jobs the two +3's below
       # need increasing
       ##

       declare -ag p

       # empty is because arrays number from 0 but jobs number from 1
       p[0]=""

       for f in 1 2 3 4 5 6; do
               p[$f]=/tmp/efivarfs_pipe${f}
               mknod ${p[$f]} p
       done

       declare -g var=$efivarfs_mount/test_multiple-$test_guid

       cleanup() {
               for f in ${p[@]}; do
                       rm -f ${f}
               done
               if [ -e $var ]; then
                       file_cleanup $var
               fi
       }
       trap cleanup exit

       waitstart() {
               cat ${p[$[$1+3]]} > /dev/null
       }

       waitpipe() {
               echo 1 > ${p[$[$1+3]]}
               cat ${p[$1]} > /dev/null
       }

       endjob() {
               echo 1 > ${p[$1]}
               wait -n %$1
       }
}

test_multiple_zero_size()
{
       ##
       # check for remove on last close, set up three threads all
       # holding the variable (one write and two reads) and then
       # close them sequentially (waiting for completion) and check
       # the state of the variable
       ##

       { waitpipe 1; echo 1; } > $var 2> /dev/null &
       waitstart 1
       # zero length file should exist
       [ -e $var ] || exit 1
       # second and third delayed close
       { waitpipe 2; } < $var &
       waitstart 2
       { waitpipe 3; } < $var &
       waitstart 3
       # close first fd
       endjob 1
       # var should only be deleted on last close
       [ -e $var ] || exit 1
       # close second fd
       endjob 2
       [ -e $var ] || exit 1
       # file should go on last close
       endjob 3
       [ ! -e $var ] || exit 1
}

test_multiple_create()
{
       ##
       # set multiple threads to access the variable but delay
       # the final write to check the close of 2 and 3.  The
       # final write should succeed in creating the variable
       ##
       { waitpipe 1; printf '\x07\x00\x00\x00\x54'; } > $var &
       waitstart 1
       [ -e $var -a ! -s $var ] || exit 1
       { waitpipe 2; } < $var &
       waitstart 2
       { waitpipe 3; } < $var &
       waitstart 3
       # close second and third fds
       endjob 2
       # var should only be created (have size) on last close
       [ -e $var -a ! -s $var ] || exit 1
       endjob 3
       [ -e $var -a ! -s $var ] || exit 1
       # close first fd
       endjob 1
       # variable should still exist
       [ -s $var ] || exit 1
       file_cleanup $var
}

test_multiple_delete_on_write() {
       ##
       # delete the variable on final write; seqencing similar
       # to test_multiple_create()
       ##
       printf '\x07\x00\x00\x00\x54' > $var
       chattr -i $var
       { waitpipe 1; printf '\x07\x00\x00\x00'; } > $var &
       waitstart 1
       [ -e $var -a -s $var ] || exit 1
       { waitpipe 2; } < $var &
       waitstart 2
       { waitpipe 3; } < $var &
       waitstart 3
       # close first fd; write should set variable size to zero
       endjob 1
       # var should only be deleted on last close
       [ -e $var -a ! -s $var ] || exit 1
       endjob 2
       [ -e $var ] || exit 1
       # close last fd
       endjob 3
       # variable should now be removed
       [ ! -e $var ] || exit 1
}

check_prereqs

rc=0
@@ -240,5 +370,9 @@ run_test test_open_unlink
run_test test_valid_filenames
run_test test_invalid_filenames
run_test test_no_set_size
setup_test_multiple
run_test test_multiple_zero_size
run_test test_multiple_create
run_test test_multiple_delete_on_write

exit $rc