Remove a partial UFS/FFS snapshot if it fails to build successfully.

When taking a UFS/FFS snapshot, it may not succeed for example if the
filesystem is too full to hold it. When a snapshot is unable to be
successfully taken, the partial snapshot should be removed.

Reported-by:  Peter Holm
Tested-by:    Peter Holm
MFC-after:    1 week
Sponsored-by: The FreeBSD Foundation
This commit is contained in:
Kirk McKusick 2023-08-09 16:43:41 -07:00
parent 219caac69a
commit c52b5d16cc

View file

@ -851,7 +851,6 @@ ffs_snapshot(struct mount *mp, char *snapfile)
free(copy_fs, M_UFSMNT);
copy_fs = NULL;
out:
NDFREE_PNBUF(&nd);
if (saved_nice > 0) {
struct proc *p;
@ -869,14 +868,30 @@ ffs_snapshot(struct mount *mp, char *snapfile)
MNT_ILOCK(mp);
mp->mnt_flag = (mp->mnt_flag & MNT_QUOTA) | (flag & ~MNT_QUOTA);
MNT_IUNLOCK(mp);
if (error)
(void) ffs_truncate(vp, (off_t)0, 0, NOCRED);
(void) ffs_syncvnode(vp, MNT_WAIT, 0);
if (error)
vput(vp);
else
VOP_UNLOCK(vp);
NDFREE_PNBUF(&nd);
vrele(nd.ni_dvp);
if (error == 0) {
(void) ffs_syncvnode(vp, MNT_WAIT, 0);
VOP_UNLOCK(vp);
} else if (VN_IS_DOOMED(vp)) {
vput(vp);
} else {
int rmerr;
/* Remove snapshot as its creation has failed. */
vput(vp);
NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_SYSSPACE,
snapfile);
if ((rmerr = namei(&nd)) != 0 ||
(rmerr = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd)) != 0)
printf("Delete of %s failed with error %d\n",
nd.ni_dirp, rmerr);
NDFREE_PNBUF(&nd);
if (nd.ni_dvp != NULL)
vput(nd.ni_dvp);
if (nd.ni_vp != NULL)
vput(nd.ni_vp);
}
vn_finished_write(wrtmp);
process_deferred_inactive(mp);
return (error);