diff options
-rw-r--r-- | sys/ufs/ffs/ffs_inode.c | 3 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_snapshot.c | 14 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_lookup.c | 14 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_vnops.c | 18 | ||||
-rw-r--r-- | sys/vm/vm_mmap.c | 2 |
5 files changed, 38 insertions, 13 deletions
diff --git a/sys/ufs/ffs/ffs_inode.c b/sys/ufs/ffs/ffs_inode.c index 4725090..30f36ee7 100644 --- a/sys/ufs/ffs/ffs_inode.c +++ b/sys/ufs/ffs/ffs_inode.c @@ -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) { diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c index af03143..ba74b31 100644 --- a/sys/ufs/ffs/ffs_snapshot.c +++ b/sys/ufs/ffs/ffs_snapshot.c @@ -241,7 +241,7 @@ restart: /* * 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 @@ restart: 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; } diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c index 3834a54..ee28d48 100644 --- a/sys/ufs/ufs/ufs_lookup.c +++ b/sys/ufs/ufs/ufs_lookup.c @@ -923,6 +923,13 @@ out: 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); } diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c index 0fac626..0c2da7d 100644 --- a/sys/ufs/ufs/ufs_vnops.c +++ b/sys/ufs/ufs/ufs_vnops.c @@ -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; diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c index b196d6f..79b6b72 100644 --- a/sys/vm/vm_mmap.c +++ b/sys/vm/vm_mmap.c @@ -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); |