Clean up the snapshot code so that it no longer depends on the use of

the SF_IMMUTABLE flag to prevent writing. Instead put in explicit
checking for the SF_SNAPSHOT flag in the appropriate places. With
this change, it is now possible to rename and link to snapshot files.
It is also possible to set or clear any of the owner, group, or
other read bits on the file, though none of the write or execute
bits can be set. There is also an explicit test to prevent the
setting or clearing of the SF_SNAPSHOT flag via chflags() or
fchflags(). Note also that the modify time cannot be changed as
it needs to accurately reflect the time that the snapshot was taken.

Submitted by:	Robert Watson <rwatson@FreeBSD.org>
This commit is contained in:
Kirk McKusick 2000-07-26 23:07:01 +00:00
parent 3ce7b7aa84
commit 3592b7155c
5 changed files with 38 additions and 13 deletions

View File

@ -45,6 +45,7 @@
#include <sys/vnode.h>
#include <sys/malloc.h>
#include <sys/resourcevar.h>
#include <sys/stat.h>
#include <vm/vm.h>
#include <vm/vm_extern.h>
@ -174,6 +175,8 @@ ffs_truncate(vp, length, flags, cred, p)
if (error)
return (error);
#endif
if ((oip->i_flags & SF_SNAPSHOT) != 0)
ffs_snapremove(ovp);
ovp->v_lasta = ovp->v_clen = ovp->v_cstart = ovp->v_lastw = 0;
if (DOINGSOFTDEP(ovp)) {
if (length > 0) {

View File

@ -241,7 +241,7 @@ ffs_snapshot(mp, snapfile)
/*
* Change inode to snapshot type file.
*/
ip->i_flags |= SF_IMMUTABLE | SF_SNAPSHOT;
ip->i_flags |= SF_SNAPSHOT;
ip->i_flag |= IN_CHANGE | IN_UPDATE;
/*
* Ensure that the snapshot is completely on disk.
@ -414,7 +414,7 @@ ffs_snapshot(mp, snapfile)
ino_to_fsbo(fs, xp->i_number);
dip->di_size = 0;
dip->di_blocks = 0;
dip->di_flags &= ~(SF_IMMUTABLE | SF_SNAPSHOT);
dip->di_flags &= ~SF_SNAPSHOT;
bzero(&dip->di_db[0], (NDADDR + NIADDR) * sizeof(ufs_daddr_t));
nbp->b_flags |= B_VALIDSUSPWRT;
bdwrite(nbp);
@ -636,11 +636,9 @@ ffs_snapremove(vp)
ip->i_copyonwrite = 0;
break;
}
if (xp == 0) {
if (xp == 0)
printf("ffs_snapremove: lost snapshot vnode %d\n",
ip->i_number);
vref(vp);
}
if (VTOI(devvp)->i_copyonwrite == 0)
devvp->v_flag &= ~VCOPYONWRITE;
/*
@ -673,9 +671,8 @@ ffs_snapremove(vp)
/*
* Clear snapshot flag and drop reference.
*/
ip->i_flags &= ~(SF_IMMUTABLE | SF_SNAPSHOT);
ip->i_flags &= ~SF_SNAPSHOT;
ip->i_flag |= IN_CHANGE | IN_UPDATE;
vrele(vp);
}
/*
@ -905,7 +902,8 @@ ffs_snapshot_unmount(mp)
while ((xp = devip->i_copyonwrite) != 0) {
devip->i_copyonwrite = xp->i_copyonwrite;
xp->i_copyonwrite = 0;
vrele(ITOV(xp));
if (xp->i_effnlink > 0)
vrele(ITOV(xp));
}
ump->um_devvp->v_flag &= ~VCOPYONWRITE;
}

View File

@ -923,6 +923,13 @@ ufs_dirremove(dvp, ip, flags, isrmdir)
error = bowrite(bp);
}
dp->i_flag |= IN_CHANGE | IN_UPDATE;
/*
* If the last named reference to a snapshot goes away,
* drop its snapshot reference so that it will be reclaimed
* when last open reference goes away.
*/
if (ip != 0 && (ip->i_flags & SF_SNAPSHOT) != 0 && ip->i_effnlink == 0)
vrele(ITOV(ip));
return (error);
}
@ -965,6 +972,13 @@ ufs_dirrewrite(dp, oip, newinum, newtype, isrmdir)
}
}
dp->i_flag |= IN_CHANGE | IN_UPDATE;
/*
* If the last named reference to a snapshot goes away,
* drop its snapshot reference so that it will be reclaimed
* when last open reference goes away.
*/
if ((oip->i_flags & SF_SNAPSHOT) != 0 && oip->i_effnlink == 0)
vrele(ITOV(oip));
return (error);
}

View File

@ -331,7 +331,7 @@ ufs_access(ap)
}
/* If immutable bit set, nobody gets to write it. */
if ((mode & VWRITE) && (ip->i_flags & IMMUTABLE))
if ((mode & VWRITE) && (ip->i_flags & (IMMUTABLE | SF_SNAPSHOT)))
return (EPERM);
/* Otherwise, user id 0 always gets access. */
@ -454,6 +454,12 @@ ufs_setattr(ap)
& (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) &&
securelevel > 0)
return (EPERM);
/* Snapshot flag cannot be set or cleared */
if (((vap->va_flags & SF_SNAPSHOT) != 0 &&
(ip->i_flags & SF_SNAPSHOT) == 0) ||
((vap->va_flags & SF_SNAPSHOT) == 0 &&
(ip->i_flags & SF_SNAPSHOT) != 0))
return (EPERM);
ip->i_flags = vap->va_flags;
} else {
if (ip->i_flags
@ -491,6 +497,8 @@ ufs_setattr(ap)
case VREG:
if (vp->v_mount->mnt_flag & MNT_RDONLY)
return (EROFS);
if ((ip->i_flags & SF_SNAPSHOT) != 0)
return (EPERM);
break;
default:
break;
@ -498,10 +506,11 @@ ufs_setattr(ap)
if ((error = UFS_TRUNCATE(vp, vap->va_size, 0, cred, p)) != 0)
return (error);
}
ip = VTOI(vp);
if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
if (vp->v_mount->mnt_flag & MNT_RDONLY)
return (EROFS);
if ((ip->i_flags & SF_SNAPSHOT) != 0)
return (EPERM);
if (cred->cr_uid != ip->i_uid &&
(error = suser_xxx(cred, p, PRISON_ROOT)) &&
((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
@ -528,6 +537,9 @@ ufs_setattr(ap)
if (vap->va_mode != (mode_t)VNOVAL) {
if (vp->v_mount->mnt_flag & MNT_RDONLY)
return (EROFS);
if ((ip->i_flags & SF_SNAPSHOT) != 0 && (vap->va_mode &
(S_IXUSR | S_IWUSR | S_IXGRP | S_IWGRP | S_IXOTH | S_IWOTH)))
return (EPERM);
error = ufs_chmod(vp, (int)vap->va_mode, cred, p);
}
VN_KNOTE(vp, NOTE_ATTRIB);
@ -702,8 +714,6 @@ ufs_remove(ap)
int error;
ip = VTOI(vp);
if ((ip->i_flags & SF_SNAPSHOT) != 0)
ffs_snapremove(vp);
if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
(VTOI(dvp)->i_flags & APPEND)) {
error = EPERM;

View File

@ -358,7 +358,7 @@ mmap(p, uap)
p->p_ucred, p)))
return (error);
if ((va.va_flags &
(IMMUTABLE|APPEND)) == 0)
(SF_SNAPSHOT|IMMUTABLE|APPEND)) == 0)
maxprot |= VM_PROT_WRITE;
else if (prot & PROT_WRITE)
return (EPERM);