Skip to content

Commit

Permalink
Mount snaphsots on <mnt>/@/<id>/m
Browse files Browse the repository at this point in the history
Instead of mounting snapshot overlays on <mnt>/@/<id>
mount them on <mnt>/@/<id>/m so as not to hide the upper
dir at <mnt>/@/<id>/u.

More changes to mount.snapshot:
- With no snapshots in stack mount pass through
  snapshot mount without creating a snapshot
- Check for overlapping snapshot mounts
  • Loading branch information
amir73il committed Dec 15, 2016
1 parent 1b40ba0 commit 24f3152
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 71 deletions.
95 changes: 41 additions & 54 deletions scripts/mount.snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
#
# Overlayfs snapshot mount helper
#
# - Create snapshot dir <mnt>/@ and snapshot 0 if non exists
# - Check if snapshots stack exists at <mnt>/@/.snapshots
# - Bind shared mount at <mnt>/@
# - Mount snapshot mount at <mnt>
# - Mount olds snapshots at <mnt>/@/<id>..
# - Mount olds snapshots at <mnt>/@/<id>/m
#
# * If any mount flags other than -o rw are passed to helper,
# it passes the command as is without doing the above
Expand Down Expand Up @@ -47,108 +47,95 @@ error()
# No support for mount options at the moment
if [ -n "$*" -a "$*" != "-o rw" ]; then
echo "$*" > /tmp/mount.snapshot.in
mount -i -t snapshot "$dev" "$mnt" $*
exit $?
exec mount -i -t snapshot "$dev" "$mnt" $*
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 - nesting is not allowed
! grep -q "^\S\+ $mnt snapshot" /proc/mounts || \
error "overlayfs snapshot already mounted at $mnt."
# 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 ( echo $m | grep -q "^$mnt" ) || ( echo $mnt | grep -q "^$m" ); then
error "overlapping overlayfs snapshot already mounted at '$m'."
fi
done
lower="$mnt"
snapdir="$mnt/@"
snapshots="$snapdir/.snapshots"
# If we create snapdir, we should remove it on failure
[ -d "$snapdir" ] || cleanup_snapdir=true

id=0
[ ! -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"
fi
cd "$lower" || exit 1
# Relative to $lower to keep overlay mount options shorter
base="@/$id"
upper="$base/u"
work="$base/w"
snap="$base"

# If we create a new snapshot, we should remove it on failure
[ -d "$snap" ] || new_snap=true
current="@/$id"
upper="$current/u"
work="$current/w"
snapmnt="$current/m"
tmpdir=/tmp/snapshot.$$
tmpsnap="$tmpdir/$id"
tmpmnt="$tmpdir/$id/m"
trap "_cleanup" 0 1 2 3 15
_cleanup()
{
err=$?
# Cleanup snapshot $id temp mounts
umount -i "$tmpsnap" 2>/dev/null
umount -i "$tmpmnt" 2>/dev/null
umount -i "$tmpdir" 2>/dev/null
umount -i "$snapdir" 2>/dev/null
rmdir $tmpdir 2>/dev/null
if [ $err != 0 ]; then
# Cleanup new created directories on failure
[ -z "$new_snap" ] || rm -rf "$mnt/$snap"
[ -z "$cleanup_snapdir" ] || rm -rf "$snapdir"
fi
exit $err
}
mount_old_snapshots()
{
local old_snapshots=$snap
local old_snapshots=$snapmnt
# mount snapshots from newest to oldest
tac "$snapshots" | while read old; do
[ "$old" != "$id" ] || continue
oldsnap="@/$old"
delsnap="@/.$old"
oldmnt=
if [ -d "$oldsnap" ]; then
# mount only non-deleted snapshots
oldmnt="$oldsnap"
elif [ -d "$delsnap" ]; then
# but chain deleted snapshot in lower
oldsnap="$delsnap"
else
continue
fi
oldmnt="$oldsnap/m"
[ -d "$oldsnap" ] || continue
old_snapshots="$oldsnap/u:$old_snapshots"
[ -n "$oldmnt" ] || continue
[ -d "$oldmnt" ] || continue
mount -i -t overlay "$dev@$old" "$oldmnt" \
-o"ro,lowerdir=$old_snapshots"
done
}
# Create new snapshot dir with empty upper/work
mkdir -p "$snap" "$upper" "$work" || exit 1
# Verify current snapshot dirs
[ -d "$snapmnt" -a -d "$upper" -a -d "$work" ] || \
error "missing snapshot '$current' directories."
# Whiteout snapshots dir inside upper
[ -c "$upper/@" ] || mknod "$upper/@" c 0 0 || exit 1
# Verify whiteout of snapshots dir inside upper
[ -c "$upper/@" ] || \
error "missing whiteout of snapshot '$current' directories."
# Make shared mount clone of the real lower mount
mount --bind "$snapdir" "$snapdir"
mount --make-shared "$snapdir"
mkdir -p "$tmpdir"
mount --bind "$snapdir" "$tmpdir"
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 snapshot overlay and snapshot mount
# Mount the current snapshot overlay and snapshot mount
mount -i -t overlay "$dev@$id" -o"lowerdir=$lower,upperdir=$upper,workdir=$work" \
"$snap" || exit 1
mount -i -t snapshot "$dev@$id" -o"upperdir=$lower,snapshot=$snap" \
"$snapmnt" || exit 1
mount -i -t snapshot "$dev@$id" -o"upperdir=$lower,snapshot=$snapmnt" \
"$mnt" || exit 1
# Write new snapshot id to snapshots stack
grep -qs "^$id$" "$snapshots" || echo "$id" >> "$snapshots"

# Bind the (now covered) snapshot overlay above the snapshot mount
mount --bind -r "$tmpsnap" "$mnt/$snap" || 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_old_snapshots
29 changes: 15 additions & 14 deletions scripts/ovlsnapshot
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ 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>
# snaphot mount points will be created as $SNAPMNT<snapshot-name>/m
SNAPMNT=$MNT/@/
# file to store snapshots stack
SNAPSHOTS="$SNAPDIR/.snapshots"
Expand Down Expand Up @@ -118,7 +118,7 @@ snapshot_in_stack()

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

snapshot_exists()
Expand All @@ -130,7 +130,7 @@ snapshot_exists()
[ -s $SNAPSHOTS ]
else
# Does snapshot $s exist?
[ -d $SNAPDIR/$s ] || [ -d $SNAPDIR/.$s ] || snapshot_in_stack $s
[ -d $SNAPDIR/$s ] || snapshot_in_stack $s
fi
}

Expand All @@ -140,6 +140,7 @@ create_snapshot()

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

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

remove_snapshot()
{
local s=$1

snapshot_is_deleted $s || delete_snapshot $s
rm -rf $SNAPDIR/.$s || exit 1
umount -i $SNAPDIR/$s/m 2>/dev/null
rm -rf $SNAPDIR/$s || exit 1
grep -v "^$1$" $SNAPSHOTS > $SNAPSHOTS.tmp
sync
mv $SNAPSHOTS.tmp $SNAPSHOTS
Expand All @@ -174,7 +175,7 @@ snapshot_is_mounted()
if [ -z "$s" ]; then
grep -q "^\S\+ $MNT snapshot" /proc/mounts
else
grep -q "^\S\+ $SNAPMNT$s overlay" /proc/mounts
grep -q "^\S\+ $SNAPMNT$s/m overlay" /proc/mounts
fi
}

Expand Down Expand Up @@ -434,7 +435,7 @@ case "$CMD" in
d=$TESTDIR
else
echo "Files in snapshot $snap:"
d=$SNAPMNT$snap/$SNAPTEST
d=$SNAPMNT$snap/m/$SNAPTEST
fi
if [ -d $d ] ; then
cd $d > /dev/null
Expand All @@ -455,15 +456,15 @@ case "$CMD" in
[ -z "$3" ] || N=$3
$0 umount $MNT
for s in $( cat $SNAPSHOTS 2> /dev/null ) ; do
$0 remove $SNAPMNT$s 2> /dev/null
$0 remove $SNAPDIR/$s 2> /dev/null
done
$0 mount $MNT
for n in $( seq 0 $N ) ; do
$0 test $MNT $n $4 || exit 1
done
$0 lstest $MNT
for n in $( seq 1 $N ) ; do
$0 lstest $SNAPMNT$n
$0 lstest $SNAPDIR/$n
done
;;
test)
Expand Down Expand Up @@ -509,7 +510,7 @@ case "$CMD" in
cd - > /dev/null
$0 lstest $MNT || exit 1
s=$n
$0 take $SNAPMNT$s || exit 1
$0 take $SNAPDIR/$s || exit 1
case "$n" in
1)
echo Create test:
Expand Down Expand Up @@ -541,12 +542,12 @@ case "$CMD" in
f=1
echo 'Restoring from snapshot' $f
rm -rf $TESTDIR/?
cp -R $SNAPMNT$f/$SNAPTEST/? $TESTDIR/
cp -R $SNAPMNT$f/m/$SNAPTEST/? $TESTDIR/
;;
esac || exit 1
echo .
$0 lstest $MNT || exit 1
$0 lstest $SNAPMNT$s || exit 1
$0 lstest $SNAPDIR/$s || exit 1
$0 list $MNT
;;

Expand Down
7 changes: 4 additions & 3 deletions scripts/umount.snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
#
# Overlayfs snapshot umount helper
#
# - Unmount snapshot overlays listed in <mnt>/@/snapshots
# - Unmount snapshot overlays <mnt>/@/*/m
# - Unmount snapshot mount at <mnt>
# - Unmount shared mount at <mnt>/@
#
#-----------------------------------------------------------------------
#
Expand Down Expand Up @@ -47,12 +48,12 @@ umount_snapshots()
{
# Unmount snapshot overlays recorded in snapshots stack
[ ! -s "$snapshots" ] || cat "$snapshots" | while read id; do
umount -i "$snapdir/$id" 2>/dev/null
umount -i "$snapdir/$id/m" 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"/* 2>/dev/null
umount -i "$snapdir"/*/m 2>/dev/null
fi
}

Expand Down

0 comments on commit 24f3152

Please sign in to comment.