Skip to content

Commit

Permalink
mount.snapshot: don't cover lower with snapshot mount
Browse files Browse the repository at this point in the history
mount snapshot mount under <lower>/@/_ because remount needs
access to the original /lower to compose new snapshot overlays.

umount/mount all snapshot overlay on snpahot mount remount.

Signed-off-by: Amir Goldstein <[email protected]>
  • Loading branch information
amir73il committed Jan 5, 2017
1 parent 2309bba commit ee777ac
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 78 deletions.
108 changes: 57 additions & 51 deletions scripts/mount.snapshot
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#!/bin/sh
# mount.snapshot <dev> <mnt>
# mount.snapshot <dev> <mnt>/@/_ -o remount
#
# Overlayfs snapshot mount helper
#
# - Check if snapshots stack exists at <mnt>/@/.snapshots
# - Bind shared mount at <mnt>/@
# - Mount snapshot mount at <mnt>
# - Mount olds snapshots at <mnt>/@/<id>/m
# - Mount (or remount) snapshot mount at <mnt>/@/_
# - Mount snapshot overlays at <mnt>/@/<id>/_
#
# * If any mount flags other than -o rw are passed to helper,
# * If any mount flags other than -o rw[,remount] are passed to helper,
# it passes the command as is without doing the above
#
#-----------------------------------------------------------------------
Expand All @@ -31,7 +31,7 @@
#-----------------------------------------------------------------------
#

dev="$1"
dev="${1%@*}"
shift
mnt="${1%/}"
shift
Expand All @@ -44,50 +44,65 @@ error()
exit 1
}

# No support for mount options at the moment
if [ -n "$1" -a "$1" != "-o" ]; then
error "invalid snapshot mount options '$*'"
fi

shift
mntopts="$1"
if [ -n "$mntopts" -a "$mntopts" != "rw" -a "$mntopts" != "rw,remount" ]; then
echo "$*" > /tmp/mount.snapshot.in
mount_internal()
{
echo "$dev $mnt -o $mntopts" > /tmp/mount.snapshot.in
exec mount -i -t snapshot "$dev" "$mnt" -o "$mntopts"
fi
}

# Verify that overlayfs snapshot feature is enabled
grep -wq 'overlay' /proc/filesystems || modprobe overlay
grep -wq 'snapshot' /proc/filesystems || \
error "overlayfs snapshots feature not enabled."

# Verify snapshot is not already mounted on child or parent path
# because nesting is not allowed
mounted=$(mount -t snapshot | while read d on m opt; do echo $m; done)
for m in $mounted; do
if [ "$m" = "$mnt" ]; then
( echo "$mntopts" | grep -q remount ) || \
# Verify that we are being called as mount helper
if [ -n "$1" -a "$1" != "-o" ]; then
error "invalid snapshot mount options '$*'"
fi

shift
mntopts="$1"
shift

if ( echo "$mntopts" | grep -q remount ) ; then
# Remount - parse <mnt> from <mnt>/_
mntdir="$mnt"
mnt="${mntdir%/@/_}"
[ "$mnt" != "$mntdir" ] || mount_internal
# helper does not parse mount options beyond rw,remount
# for mounting the current snapshot after snapshot take
mntopts="rw,remount"
# snapshot overlays do not support remount -
# they have to be umounted/mounted
umount -i "$mnt"/@/*/_ 2>/dev/null
else
mntdir="$mnt/@/_"
# helper does not parse mount options beyond rw
[ -z "$mntopts" -o "$mntopts" = "rw" ] || mount_internal
# Verify snapshot is not already mounted on <mnt>/_
mount -t snapshot | while read d on m opt; do
[ "$m" != "$mntdir" -a "$m" != "$mnt" ] || \
error "overlayfs snapshot already mounted at '$m'."
elif ( echo $m | grep -q "^$mnt" ) || ( echo $mnt | grep -q "^$m" ); then
error "overlapping overlayfs snapshot already mounted at '$m'."
fi
done
done

lower="$mnt"
snapdir="$mnt/@"
snapshots="$snapdir/.snapshots"
mkdir -p "$mntdir" || \
error "failed mkdir '"$mntdir"' for overlayfs snapshot."
fi

# Disable redirect_dir because of rename issue with multiple snapshots:
# https://github.com/amir73il/overlayfs/issues/1
mntopts="$mntopts,redirect_dir=off"
snapmntopts="redirect_dir=off"
oldsnapmntopts="redirect_dir=off"

lower="$mnt"
snapdir="$mnt/@"
snapshots="$snapdir/.snapshots"
[ ! -s "$snapshots" ] || id=$(tail -n 1 "$snapshots")

if [ -z "$id" ]; then
# No current snapshot - mount pass through snapshot mount
exec mount -i -t snapshot "$dev" "$mnt" -o"upperdir=$lower,$mntopts"
exec mount -i -t snapshot "$dev@" "$mntdir" -o"upperdir=$lower,$mntopts"
fi

cd "$lower" || exit 1
Expand All @@ -96,19 +111,14 @@ cd "$lower" || exit 1
current="@/$id"
upper="$current/u"
work="$current/w"
snapmnt="$current/m"
snapmnt="$current/_"

tmpdir=/tmp/snapshot.$$
tmpmnt="$tmpdir/$id/m"
trap "_cleanup" 0 1 2 3 15
_cleanup()
{
err=$?
# Cleanup snapshot $id temp mounts
umount -i "$tmpmnt" 2>/dev/null
umount -i "$tmpdir" 2>/dev/null
umount -i "$snapdir" 2>/dev/null
rmdir $tmpdir 2>/dev/null
# Cleanup snapshot overlay mounts if snapshot mount failed
[ $err = 0 ] || umount -i "$snapdir"/*/_ 2>/dev/null
exit $err
}

Expand All @@ -120,7 +130,7 @@ mount_old_snapshots()
tac "$snapshots" | while read old; do
[ "$old" != "$id" ] || continue
oldsnap="@/$old"
oldmnt="$oldsnap/m"
oldmnt="$oldsnap/_"
[ -d "$oldsnap" ] || continue
old_snapshots="$oldsnap/u:$old_snapshots"
[ -d "$oldmnt" ] || continue
Expand All @@ -137,20 +147,16 @@ mount_old_snapshots()
[ -c "$upper/@" ] || \
error "missing whiteout of snapshot '$current' directories."

# Make shared mount clone of the real lower mount
mount --bind "$snapdir" "$snapdir" || exit 1
mount --make-shared "$snapdir" || exit 1
mkdir -p "$tmpdir" || exit 1
mount --bind "$snapdir" "$tmpdir" || exit 1
# Mount the current snapshot overlay and snapshot mount
# Mount the current snapshot overlay
mount -i -t overlay "$dev@$id" "$snapmnt" \
-o"lowerdir=$lower,upperdir=$upper,workdir=$work,$snapmntopts" || exit 1
mount -i -t snapshot "$dev@$id" "$mnt" \
-o"upperdir=$lower,snapshot=$snapmnt,$mntopts" || exit 1
# Bind the (now covered) current snapshot overlay above the snapshot mount
mount --bind -r "$tmpmnt" "$mnt/$snapmnt" || exit 1

# Mount older snapshots
# Mount older snapshot overlays
mount_old_snapshots

# Mount the snapshot mount
mount -i -t snapshot "$dev@" "$mntdir" \
-o"upperdir=$lower,snapshot=$snapmnt,$mntopts" || exit 1

# Remount current snapshot overlay read-only
mount -o remount,ro "$snapmnt" || exit 1
30 changes: 16 additions & 14 deletions scripts/ovlsnapshot
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,9 @@ parse_path_snapshot_arg()
# directory inside <path> to store snapshot related files
SNAPDIR=$MNT/@
# directory prefix for snapshot mount points
# snaphot mount points will be created as $SNAPMNT<snapshot-name>/m
SNAPMNT=$MNT/@/
# snaphot mount points will be created as $SNAPROOT/<snapshot-name>/_
SNAPROOT=$MNT/@
SNAPMNT=$SNAPROOT/_
# file to store snapshots stack
SNAPSHOTS="$SNAPDIR/.snapshots"

Expand All @@ -86,7 +87,7 @@ parse_path_snapshot_arg()
export MNT
S=$MNT@$snap
SNAPTEST="ovlsnaptest"
TESTDIR="$MNT/$SNAPTEST"
TESTDIR="$SNAPMNT/$SNAPTEST"
}

current_snapshot()
Expand Down Expand Up @@ -118,7 +119,7 @@ snapshot_in_stack()

snapshot_is_deleted()
{
[ ! -d $SNAPDIR/$1/m ]
[ ! -d $SNAPDIR/$1/_ ]
}

snapshot_exists()
Expand All @@ -140,7 +141,7 @@ create_snapshot()

mkdir -p $SNAPDIR/$s/u || exit 1
mkdir -p $SNAPDIR/$s/w || exit 1
mkdir -p $SNAPDIR/$s/m || exit 1
mkdir -p $SNAPDIR/$s/_ || exit 1
mknod $SNAPDIR/$s/u/@ c 0 0 || exit 1
echo $s >> $SNAPSHOTS || exit 1
sync
Expand All @@ -150,17 +151,17 @@ delete_snapshot()
{
local s=$1

umount -i $SNAPDIR/$s/m 2>/dev/null
umount -i $SNAPDIR/$s/_ 2>/dev/null
rm -rf $SNAPDIR/$s/w || exit 1
rm -rf $SNAPDIR/$s/m || exit 1
rm -rf $SNAPDIR/$s/_ || exit 1
sync
}

remove_snapshot()
{
local s=$1

umount -i $SNAPDIR/$s/m 2>/dev/null
umount -i $SNAPDIR/$s/_ 2>/dev/null
rm -rf $SNAPDIR/$s || exit 1
grep -v "^$1$" $SNAPSHOTS > $SNAPSHOTS.tmp
sync
Expand All @@ -173,9 +174,9 @@ snapshot_is_mounted()
local s=$1

if [ -z "$s" ]; then
grep -q "^\S\+ $MNT snapshot" /proc/mounts
grep -q "^\S\+ $SNAPMNT snapshot" /proc/mounts
else
grep -q "^\S\+ $SNAPMNT$s/m overlay" /proc/mounts
grep -q "^\S\+ $SNAPROOT/$s/_ overlay" /proc/mounts
fi
}

Expand All @@ -188,13 +189,14 @@ mount_snapshot()
umount_snapshot()
{
snapshot_is_mounted || return
umount $MNT || exit 1
umount $SNAPMNT || exit 1
}

remount_snapshot()
{
snapshot_is_mounted || return
# remount with -osnapshot=$(current_snapshot)
mount -t snapshot snapshot $MNT -o remount || exit 1
mount $SNAPMNT -o remount || exit 1
}

umount_all_mounted_snapshots()
Expand Down Expand Up @@ -457,7 +459,7 @@ case "$CMD" in
d=$TESTDIR
else
echo "Files in snapshot $snap:"
d=$SNAPMNT$snap/m/$SNAPTEST
d=$SNAPROOT/$snap/_/$SNAPTEST
fi
if [ -d $d ] ; then
cd $d > /dev/null
Expand Down Expand Up @@ -571,7 +573,7 @@ case "$CMD" in
f=1
echo 'Restoring from snapshot' $f
rm -rf $TESTDIR/?
cp -R $SNAPMNT$f/m/$SNAPTEST/? $TESTDIR/
cp -R $SNAPROOT/$f/_/$SNAPTEST/? $TESTDIR/
;;
esac || exit 1
cd $TESTDIR > /dev/null
Expand Down
25 changes: 12 additions & 13 deletions scripts/umount.snapshot
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
#!/bin/sh
# umount.snapshot <mnt>
# umount.snapshot <mnt>/@/_
#
# Overlayfs snapshot umount helper
#
# - Unmount snapshot overlays <mnt>/@/*/m
# - Unmount snapshot mount at <mnt>
# - Unmount shared mount at <mnt>/@
# - Unmount snapshot overlays <mnt>/@/*/_
# - Unmount snapshot mount at <mnt>/@/_
#
#-----------------------------------------------------------------------
#
Expand All @@ -31,11 +30,15 @@ mnt="${1%/}"

[ -d "$mnt" ] || exit 1

mntdir="$mnt"
mnt="${mntdir%/@/_}"

# umount.snapshot helper should not take care of mounts
# not created by mount.snapshot helper. Use the <dev>@<id>
# not created by mount.snapshot helper. Use the <dev>@*
# dev argument as indication to helper aided snapshot mount.
# If this is an unfamiliar snapshot mount - bypass helper.
if ! grep -q "^\S\+@\S\+ $mnt snapshot" /proc/mounts; then
if [ "$mnt" = "$mntdir" ] || \
! grep -q "^\S\+@.* $mntdir snapshot" /proc/mounts; then
echo "$*" > /tmp/umount.snapshot.in
umount -i $*
exit $?
Expand All @@ -48,18 +51,14 @@ umount_snapshots()
{
# Unmount snapshot overlays recorded in snapshots stack
[ ! -s "$snapshots" ] || cat "$snapshots" | while read id; do
umount -i "$snapdir/$id/m" 2>/dev/null
umount -i "$snapdir/$id/_" 2>/dev/null
done

# Cleanup leftover snapshot overlays not recorded in snapshots stack
if grep -q "^\S\+@\S\+ $snapdir/\S\+ overlay" /proc/mounts; then
umount -i "$snapdir"/*/m 2>/dev/null
umount -i "$snapdir"/*/_ 2>/dev/null
fi
}

umount_snapshots
umount -i "$mnt"
# Repeat in case mount.snapshot cleanup failed
umount_snapshots
# Unmount the shared snapshots dir
umount -i "$snapdir"
umount -i "$mntdir"

0 comments on commit ee777ac

Please sign in to comment.