| # |
| # overlayfs specific common functions. |
| # |
| . ./common/module |
| |
| # Export overlayfs xattrs and constant value |
| export OVL_XATTR_OPAQUE="trusted.overlay.opaque" |
| export OVL_XATTR_REDIRECT="trusted.overlay.redirect" |
| export OVL_XATTR_IMPURE="trusted.overlay.impure" |
| export OVL_XATTR_ORIGIN="trusted.overlay.origin" |
| export OVL_XATTR_NLINK="trusted.overlay.nlink" |
| export OVL_XATTR_UPPER="trusted.overlay.upper" |
| export OVL_XATTR_METACOPY="trusted.overlay.metacopy" |
| |
| # helper function to do the actual overlayfs mount operation |
| _overlay_mount_dirs() |
| { |
| local lowerdir=$1 |
| local upperdir=$2 |
| local workdir=$3 |
| shift 3 |
| |
| $MOUNT_PROG -t overlay -o lowerdir=$lowerdir -o upperdir=$upperdir \ |
| -o workdir=$workdir `_common_dev_mount_options $*` |
| } |
| |
| # Mount with same options/mnt/dev of scratch mount, but optionally |
| # with different lower/upper/work dirs |
| _overlay_scratch_mount_dirs() |
| { |
| local lowerdir=$1 |
| local upperdir=$2 |
| local workdir=$3 |
| shift 3 |
| |
| _overlay_mount_dirs $lowerdir $upperdir $workdir \ |
| $* $OVL_BASE_SCRATCH_MNT $SCRATCH_MNT |
| } |
| |
| _overlay_mkdirs() |
| { |
| local dir=$1 |
| |
| mkdir -p $dir/$OVL_UPPER |
| mkdir -p $dir/$OVL_LOWER |
| mkdir -p $dir/$OVL_WORK |
| mkdir -p $dir/$OVL_MNT |
| } |
| |
| # Given a base fs dir, set up overlay directories and mount on the given mnt. |
| # The dir is used as the mount device so it can be seen from df or mount |
| _overlay_mount() |
| { |
| local dir=$1 |
| local mnt=$2 |
| shift 2 |
| |
| _supports_filetype $dir || _notrun "upper fs needs to support d_type" |
| |
| _overlay_mkdirs $dir |
| |
| _overlay_mount_dirs $dir/$OVL_LOWER $dir/$OVL_UPPER $dir/$OVL_WORK \ |
| $* $dir $mnt |
| } |
| |
| _overlay_base_mount() |
| { |
| local devname=$1 |
| local mntname=$2 |
| local dev=$3 |
| local mnt=$4 |
| shift 4 |
| |
| if [ -z "$dev" -o -z "$mnt" ] || \ |
| _check_mounted_on $devname $dev $mntname $mnt; then |
| _idmapped_mount $dev $mnt |
| # no base fs or already mounted |
| return 0 |
| elif [ $? -ne 1 ]; then |
| # base fs mounted but not on mount point |
| return 1 |
| fi |
| |
| _mount $* $dev $mnt |
| _idmapped_mount $dev $mnt |
| } |
| |
| _overlay_base_test_mount() |
| { |
| _overlay_base_mount OVL_BASE_TEST_DEV OVL_BASE_TEST_DIR \ |
| "$OVL_BASE_TEST_DEV" "$OVL_BASE_TEST_DIR" \ |
| $TEST_FS_MOUNT_OPTS $SELINUX_MOUNT_OPTIONS |
| } |
| |
| _overlay_test_mount() |
| { |
| _overlay_base_test_mount && \ |
| _overlay_mount $OVL_BASE_TEST_DIR $TEST_DIR $* |
| } |
| |
| _overlay_base_scratch_mount() |
| { |
| _overlay_base_mount OVL_BASE_SCRATCH_DEV OVL_BASE_SCRATCH_MNT \ |
| "$OVL_BASE_SCRATCH_DEV" "$OVL_BASE_SCRATCH_MNT" \ |
| $OVL_BASE_MOUNT_OPTIONS $SELINUX_MOUNT_OPTIONS |
| } |
| |
| _overlay_scratch_mount() |
| { |
| if echo "$*" | grep -q remount; then |
| $MOUNT_PROG $SCRATCH_MNT $* |
| return |
| fi |
| |
| _overlay_base_scratch_mount && \ |
| _overlay_mount $OVL_BASE_SCRATCH_MNT $SCRATCH_MNT $* |
| } |
| |
| _overlay_base_unmount() |
| { |
| local dev=$1 |
| local mnt=$2 |
| |
| [ -n "$dev" -a -n "$mnt" ] || return 0 |
| |
| $UMOUNT_PROG $mnt |
| } |
| |
| _overlay_test_unmount() |
| { |
| $UMOUNT_PROG $TEST_DIR |
| _overlay_base_unmount "$OVL_BASE_TEST_DEV" "$OVL_BASE_TEST_DIR" |
| } |
| |
| _overlay_scratch_unmount() |
| { |
| $UMOUNT_PROG $SCRATCH_MNT |
| _overlay_base_unmount "$OVL_BASE_SCRATCH_DEV" "$OVL_BASE_SCRATCH_MNT" |
| } |
| |
| # Check that a specific overlayfs feature is supported |
| _check_overlay_feature() |
| { |
| local feature=$1 |
| local dev=$2 |
| local mnt=$3 |
| |
| # overalyfs features (e.g. redirect_dir, index) are |
| # configurable from Kconfig (the build default), by module |
| # parameter (the system default) and per mount by mount |
| # option ${feature}=[on|off]. |
| local default=`_get_fs_module_param ${feature}` |
| [ "$default" = Y ] || [ "$default" = N ] || \ |
| _notrun "feature '${feature}' not supported by ${FSTYP}" |
| |
| # Check options to be sure. For example, Overlayfs will fallback to |
| # index=off if underlying fs does not support file handles. |
| # Overlayfs only displays mount option if it differs from the default. |
| # Overlayfs may enable the feature, but fallback to read-only mount. |
| ((( [ "$default" = N ] && _fs_options $dev | grep -q "${feature}=on" ) || \ |
| ( [ "$default" = Y ] && ! _fs_options $dev | grep -q "${feature}=off" )) && \ |
| touch $mnt/foo 2>/dev/null ) || \ |
| _notrun "${FSTYP} feature '${feature}' cannot be enabled on ${dev}" |
| } |
| |
| # Require a set of overlayfs features |
| _require_scratch_overlay_features() |
| { |
| local features=( $* ) |
| local opts="rw" |
| |
| for feature in ${features[*]}; do |
| # If the module parameter does not exist then there is no |
| # point in checking the mount option. |
| _get_fs_module_param ${feature} > /dev/null 2>&1 || \ |
| _notrun "feature '${feature}' not supported by overlay" |
| opts+=",${feature}=on" |
| done |
| |
| _scratch_mkfs > /dev/null 2>&1 |
| _try_scratch_mount -o $opts || \ |
| _notrun "overlay features '${features[*]}' cannot be enabled on ${SCRATCH_DEV}" |
| |
| for feature in ${features[*]}; do |
| _check_overlay_feature ${feature} $SCRATCH_DEV $SCRATCH_MNT |
| done |
| |
| _scratch_unmount |
| } |
| |
| # Helper function to check underlying dirs of overlay filesystem |
| _overlay_fsck_dirs() |
| { |
| local lowerdir=$1 |
| local upperdir=$2 |
| local workdir=$3 |
| shift 3 |
| |
| [[ ! -x "$FSCK_OVERLAY_PROG" ]] && return 0 |
| |
| $FSCK_OVERLAY_PROG -o lowerdir=$lowerdir -o upperdir=$upperdir \ |
| -o workdir=$workdir $* |
| } |
| |
| # Run fsck and check for expected return value |
| _overlay_fsck_expect() |
| { |
| # The first arguments is the expected fsck program exit code, the |
| # remaining arguments are the input parameters of the fsck program. |
| local expect_ret=$1 |
| local lowerdir=$2 |
| local upperdir=$3 |
| local workdir=$4 |
| shift 4 |
| |
| _overlay_fsck_dirs $lowerdir $upperdir $workdir $* >> \ |
| $seqres.full 2>&1 |
| fsck_ret=$? |
| |
| [[ "$fsck_ret" == "$expect_ret" ]] || \ |
| echo "expect fsck.overlay to return $expect_ret, but got $fsck_ret" |
| } |
| |
| _overlay_check_dirs() |
| { |
| local lowerdir=$1 |
| local upperdir=$2 |
| local workdir=$3 |
| shift 3 |
| local err=0 |
| |
| _overlay_fsck_dirs $lowerdir $upperdir $workdir \ |
| $FSCK_OPTIONS $* >>$tmp.fsck 2>&1 |
| if [ $? -ne 0 ]; then |
| _log_err "_overlay_check_fs: overlayfs on $lowerdir,$upperdir,$workdir is inconsistent" |
| |
| echo "*** fsck.overlay output ***" >>$seqres.full |
| cat $tmp.fsck >>$seqres.full |
| echo "*** end fsck.overlay output" >>$seqres.full |
| |
| echo "*** mount output ***" >>$seqres.full |
| _mount >>$seqres.full |
| echo "*** end mount output" >>$seqres.full |
| |
| err=1 |
| fi |
| rm -f $tmp.fsck |
| |
| return $err |
| } |
| |
| # Check the same mnt/dev of _check_overlay_scratch_fs but non-default |
| # underlying scratch dirs of overlayfs, it needs lower/upper/work dirs |
| # provided as arguments, and it's useful for non-default setups such |
| # as multiple lower layers |
| _overlay_check_scratch_dirs() |
| { |
| local lowerdir=$1 |
| local upperdir=$2 |
| local workdir=$3 |
| shift 3 |
| |
| # Need to umount overlay for scratch dir check |
| local ovl_mounted=`_is_dir_mountpoint $SCRATCH_MNT` |
| [ -z "$ovl_mounted" ] || $UMOUNT_PROG $SCRATCH_MNT |
| |
| # Check dirs with extra overlay options |
| _overlay_check_dirs $lowerdir $upperdir $workdir $* |
| local ret=$? |
| |
| if [ $ret -eq 0 -a -n "$ovl_mounted" ]; then |
| # overlay was mounted, remount with extra mount options |
| _overlay_scratch_mount_dirs $lowerdir $upperdir \ |
| $workdir $* |
| ret=$? |
| fi |
| |
| return $ret |
| } |
| |
| _overlay_check_fs() |
| { |
| # The first arguments is overlay mount point use for checking |
| # overlay filesystem is mounted or not, the remaining arquments |
| # use for mounting overlay base filesystem if it was not mounted. |
| # We shift one to aligns arguments for _overlay_base_mount. |
| local ovl_mnt=$1 |
| shift 1 |
| |
| local base_dev=$3 |
| local base_mnt=$4 |
| |
| [ "$FSTYP" = overlay ] || return 0 |
| |
| # Base fs needs to be mounted to check overlay dirs |
| local base_fstype="" |
| local ovl_mounted="" |
| |
| [ -z "$base_dev" ] || \ |
| base_fstype=`_fs_type $base_dev` |
| |
| # If base_dev is set but base_fstype is empty, base fs is not |
| # mounted, we need to mount base fs. Otherwise, we need to |
| # check and umount overlayfs if it was mounted. |
| if [ -n "$base_dev" -a -z "$base_fstype" ]; then |
| _overlay_base_mount $* |
| else |
| # Check and umount overlay for dir check |
| ovl_mounted=`_is_dir_mountpoint $ovl_mnt` |
| [ -z "$ovl_mounted" ] || $UMOUNT_PROG $ovl_mnt |
| fi |
| |
| _overlay_check_dirs $base_mnt/$OVL_LOWER $base_mnt/$OVL_UPPER \ |
| $base_mnt/$OVL_WORK |
| local ret=$? |
| |
| if [ -n "$base_dev" -a -z "$base_fstype" ]; then |
| _overlay_base_unmount "$base_dev" "$base_mnt" |
| elif [ $ret -eq 0 -a -n "$ovl_mounted" ]; then |
| # overlay was mounted, remount besides extra mount options |
| _overlay_mount $base_mnt $ovl_mnt |
| ret=$? |
| fi |
| |
| if [ $ret != 0 ]; then |
| status=1 |
| if [ "$iam" != "check" ]; then |
| exit 1 |
| fi |
| return 1 |
| fi |
| |
| return 0 |
| } |
| |
| _check_overlay_test_fs() |
| { |
| _overlay_check_fs "$TEST_DIR" \ |
| OVL_BASE_TEST_DEV OVL_BASE_TEST_DIR \ |
| "$OVL_BASE_TEST_DEV" "$OVL_BASE_TEST_DIR" \ |
| $TEST_FS_MOUNT_OPTS $SELINUX_MOUNT_OPTIONS |
| } |
| |
| _check_overlay_scratch_fs() |
| { |
| _overlay_check_fs "$SCRATCH_MNT" \ |
| OVL_BASE_SCRATCH_DEV OVL_BASE_SCRATCH_MNT \ |
| "$OVL_BASE_SCRATCH_DEV" "$OVL_BASE_SCRATCH_MNT" \ |
| $OVL_BASE_MOUNT_OPTIONS $SELINUX_MOUNT_OPTIONS |
| } |
| |
| _repair_overlay_scratch_fs() |
| { |
| _overlay_fsck_dirs $OVL_BASE_SCRATCH_MNT/$OVL_LOWER \ |
| $OVL_BASE_SCRATCH_MNT/$OVL_UPPER \ |
| $OVL_BASE_SCRATCH_MNT/$OVL_WORK -y |
| local res=$? |
| case $res in |
| $FSCK_OK|$FSCK_NONDESTRUCT) |
| res=0 |
| ;; |
| *) |
| _dump_err2 "fsck.overlay failed, err=$res" |
| ;; |
| esac |
| return $res |
| } |
| |
| # This test requires that unionmount testsuite is installed at |
| # $UNIONMOUNT_TESTSUITE and that it supports configuring layers and overlay |
| # mount paths via UNIONMOUNT_* environment variables. |
| _require_unionmount_testsuite() |
| { |
| [ -x "$UNIONMOUNT_TESTSUITE/run" ] || \ |
| _notrun "unionmount testsuite required." |
| |
| # Verify that UNIONMOUNT_* vars are supported |
| local usage=`UNIONMOUNT_BASEDIR=_ "$UNIONMOUNT_TESTSUITE/run" 2>&1` |
| echo $usage | grep -wq "UNIONMOUNT_BASEDIR" || \ |
| _notrun "newer version of unionmount testsuite required." |
| |
| [ -n "$OVERLAY_MOUNT_OPTIONS" ] || return |
| # If custom overlay mount options are used |
| # verify that UNIONMOUNT_MNTOPTIONS var is supported |
| local usage=`UNIONMOUNT_MNTOPTIONS=_ "$UNIONMOUNT_TESTSUITE/run" 2>&1` |
| echo $usage | grep -wq "UNIONMOUNT_MNTOPTIONS" || \ |
| _notrun "newer version of unionmount testsuite required to support OVERLAY_MOUNT_OPTIONS." |
| } |
| |
| _unionmount_testsuite_run() |
| { |
| [ "$FSTYP" = overlay ] || \ |
| _notrun "Filesystem $FSTYP not supported with unionmount testsuite." |
| |
| # Provide the mounted base fs for upper and lower dirs and the |
| # overlay mount point. |
| # unionmount testsuite will perform the overlay mount. |
| # test fs is used for lower layer in non-samefs runs. |
| # scratch fs is used for upper layer in non-samefs runs and |
| # for both layers in samefs runs. |
| if (echo $* | grep -qv samefs) ; then |
| _overlay_base_test_mount |
| export UNIONMOUNT_LOWERDIR=$OVL_BASE_TEST_DIR/union |
| fi |
| export UNIONMOUNT_BASEDIR=$OVL_BASE_SCRATCH_MNT/union |
| export UNIONMOUNT_MNTOPTIONS="$OVERLAY_MOUNT_OPTIONS" |
| |
| _scratch_mkfs |
| rm -rf $UNIONMOUNT_BASEDIR $UNIONMOUNT_LOWERDIR |
| mkdir -p $UNIONMOUNT_BASEDIR $UNIONMOUNT_LOWERDIR |
| |
| cd $UNIONMOUNT_TESTSUITE |
| echo "run $* ..." > $seqres.full |
| ./run $* >> $seqres.full || \ |
| echo "unionmount testsuite failed! see $seqres.full for details." |
| } |
| |
| _unionmount_testsuite_cleanup() |
| { |
| cd / |
| rm -f $tmp.* |
| |
| [ -n "$UNIONMOUNT_BASEDIR" ] || return 0 |
| |
| # Cleanup overlay mount after unionmount testsuite run |
| cd $UNIONMOUNT_TESTSUITE |
| echo "run --clean-up ..." >> $seqres.full |
| ./run --clean-up >> $seqres.full 2>&1 |
| } |