summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/ufs/ffs/ffs_inode.c3
-rw-r--r--sys/ufs/ffs/ffs_snapshot.c14
-rw-r--r--sys/ufs/ufs/ufs_lookup.c14
-rw-r--r--sys/ufs/ufs/ufs_vnops.c18
-rw-r--r--sys/vm/vm_mmap.c2
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);
OpenPOWER on IntegriCloud