aboutsummaryrefslogtreecommitdiff
path: root/sys/ufs
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2009-09-17 16:16:44 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2009-09-17 16:16:44 +0000
commit10b3b54548f2290bbe8d8f88c59c28d12b7a635d (patch)
treedea5b87c905a5175efdc56037f61b7ecb2031d98 /sys/ufs
parentd190eb2e36c4fabd7234d7ece4e44f4b554b35fb (diff)
parente330a6a59e2df7a34b1ee94602e162b07e4e8a9e (diff)
downloadsrc-10b3b54548f2290bbe8d8f88c59c28d12b7a635d.tar.gz
src-10b3b54548f2290bbe8d8f88c59c28d12b7a635d.zip
Merge from head
Notes
Notes: svn path=/projects/quota64/; revision=197292
Diffstat (limited to 'sys/ufs')
-rw-r--r--sys/ufs/ffs/ffs_alloc.c14
-rw-r--r--sys/ufs/ffs/ffs_snapshot.c5
-rw-r--r--sys/ufs/ffs/ffs_softdep.c61
-rw-r--r--sys/ufs/ffs/ffs_vfsops.c64
-rw-r--r--sys/ufs/ffs/ffs_vnops.c194
-rw-r--r--sys/ufs/ufs/dinode.h5
-rw-r--r--sys/ufs/ufs/dirhash.h2
-rw-r--r--sys/ufs/ufs/extattr.h2
-rw-r--r--sys/ufs/ufs/inode.h4
-rw-r--r--sys/ufs/ufs/ufs_acl.c289
-rw-r--r--sys/ufs/ufs/ufs_dirhash.c138
-rw-r--r--sys/ufs/ufs/ufs_extattr.c7
-rw-r--r--sys/ufs/ufs/ufs_extern.h3
-rw-r--r--sys/ufs/ufs/ufs_lookup.c152
-rw-r--r--sys/ufs/ufs/ufs_vfsops.c8
-rw-r--r--sys/ufs/ufs/ufs_vnops.c81
16 files changed, 660 insertions, 369 deletions
diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c
index 4748f682101c..b4f001e6c677 100644
--- a/sys/ufs/ffs/ffs_alloc.c
+++ b/sys/ufs/ffs/ffs_alloc.c
@@ -326,10 +326,9 @@ retry:
ip->i_flag |= IN_CHANGE | IN_UPDATE;
allocbuf(bp, nsize);
bp->b_flags |= B_DONE;
- if ((bp->b_flags & (B_MALLOC | B_VMIO)) != B_VMIO)
- bzero((char *)bp->b_data + osize, nsize - osize);
- else
- vfs_bio_clrbuf(bp);
+ bzero(bp->b_data + osize, nsize - osize);
+ if ((bp->b_flags & (B_MALLOC | B_VMIO)) == B_VMIO)
+ vfs_bio_set_valid(bp, osize, nsize - osize);
*bpp = bp;
return (0);
}
@@ -404,10 +403,9 @@ retry:
ip->i_flag |= IN_CHANGE | IN_UPDATE;
allocbuf(bp, nsize);
bp->b_flags |= B_DONE;
- if ((bp->b_flags & (B_MALLOC | B_VMIO)) != B_VMIO)
- bzero((char *)bp->b_data + osize, nsize - osize);
- else
- vfs_bio_clrbuf(bp);
+ bzero(bp->b_data + osize, nsize - osize);
+ if ((bp->b_flags & (B_MALLOC | B_VMIO)) == B_VMIO)
+ vfs_bio_set_valid(bp, osize, nsize - osize);
*bpp = bp;
return (0);
}
diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c
index dff56edeb783..a6e73f53c5fc 100644
--- a/sys/ufs/ffs/ffs_snapshot.c
+++ b/sys/ufs/ffs/ffs_snapshot.c
@@ -278,7 +278,6 @@ restart:
return (error);
goto restart;
}
- VOP_LEASE(nd.ni_dvp, td, KERNCRED, LEASE_WRITE);
error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vat);
VOP_UNLOCK(nd.ni_dvp, 0);
if (error) {
@@ -2229,7 +2228,7 @@ ffs_copyonwrite(devvp, bp)
VI_UNLOCK(devvp);
if (saved_runningbufspace != 0) {
bp->b_runningbufspace = saved_runningbufspace;
- atomic_add_int(&runningbufspace,
+ atomic_add_long(&runningbufspace,
bp->b_runningbufspace);
}
return (0); /* Snapshot gone */
@@ -2354,7 +2353,7 @@ ffs_copyonwrite(devvp, bp)
*/
if (saved_runningbufspace != 0) {
bp->b_runningbufspace = saved_runningbufspace;
- atomic_add_int(&runningbufspace, bp->b_runningbufspace);
+ atomic_add_long(&runningbufspace, bp->b_runningbufspace);
}
return (error);
}
diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c
index 15ceef812c59..4d652c114dd1 100644
--- a/sys/ufs/ffs/ffs_softdep.c
+++ b/sys/ufs/ffs/ffs_softdep.c
@@ -556,8 +556,8 @@ MTX_SYSINIT(softdep_lock, &lk, "Softdep Lock", MTX_DEF);
#define ACQUIRE_LOCK(lk) mtx_lock(lk)
#define FREE_LOCK(lk) mtx_unlock(lk)
-#define BUF_AREC(bp) ((bp)->b_lock.lock_object.lo_flags |= LK_CANRECURSE)
-#define BUF_NOREC(bp) ((bp)->b_lock.lock_object.lo_flags &= ~LK_CANRECURSE)
+#define BUF_AREC(bp) ((bp)->b_lock.lock_object.lo_flags |= LO_RECURSABLE)
+#define BUF_NOREC(bp) ((bp)->b_lock.lock_object.lo_flags &= ~LO_RECURSABLE)
/*
* Worklist queue management.
@@ -663,6 +663,8 @@ static int req_clear_inodedeps; /* syncer process flush some inodedeps */
static int req_clear_remove; /* syncer process flush some freeblks */
#define FLUSH_REMOVE 2
#define FLUSH_REMOVE_WAIT 3
+static long num_freeblkdep; /* number of freeblks workitems allocated */
+
/*
* runtime statistics
*/
@@ -2223,6 +2225,9 @@ softdep_setup_freeblocks(ip, length, flags)
freeblks->fb_uid = ip->i_uid;
freeblks->fb_previousinum = ip->i_number;
freeblks->fb_devvp = ip->i_devvp;
+ ACQUIRE_LOCK(&lk);
+ num_freeblkdep++;
+ FREE_LOCK(&lk);
extblocks = 0;
if (fs->fs_magic == FS_UFS2_MAGIC)
extblocks = btodb(fragroundup(fs, ip->i_din2->di_extsize));
@@ -2815,6 +2820,7 @@ handle_workitem_freeblocks(freeblks, flags)
ACQUIRE_LOCK(&lk);
WORKITEM_FREE(freeblks, D_FREEBLKS);
+ num_freeblkdep--;
FREE_LOCK(&lk);
}
@@ -3309,7 +3315,7 @@ newdirrem(bp, dp, ip, isrmdir, prevdirremp)
* the number of freefile and freeblks structures.
*/
ACQUIRE_LOCK(&lk);
- if (num_dirrem > max_softdeps / 2)
+ if (!(ip->i_flags & SF_SNAPSHOT) && num_dirrem > max_softdeps / 2)
(void) request_cleanup(ITOV(dp)->v_mount, FLUSH_REMOVE);
num_dirrem += 1;
FREE_LOCK(&lk);
@@ -5102,10 +5108,30 @@ softdep_fsync(vp)
FREE_LOCK(&lk);
if (ffs_vgetf(mp, parentino, LK_NOWAIT | LK_EXCLUSIVE, &pvp,
FFSV_FORCEINSMQ)) {
+ error = vfs_busy(mp, MBF_NOWAIT);
+ if (error != 0) {
+ vfs_ref(mp);
+ VOP_UNLOCK(vp, 0);
+ error = vfs_busy(mp, 0);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+ vfs_rel(mp);
+ if (error != 0)
+ return (ENOENT);
+ if (vp->v_iflag & VI_DOOMED) {
+ vfs_unbusy(mp);
+ return (ENOENT);
+ }
+ }
VOP_UNLOCK(vp, 0);
error = ffs_vgetf(mp, parentino, LK_EXCLUSIVE,
&pvp, FFSV_FORCEINSMQ);
+ vfs_unbusy(mp);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+ if (vp->v_iflag & VI_DOOMED) {
+ if (error == 0)
+ vput(pvp);
+ error = ENOENT;
+ }
if (error != 0)
return (error);
}
@@ -5748,7 +5774,8 @@ softdep_slowdown(vp)
max_softdeps_hard = max_softdeps * 11 / 10;
if (num_dirrem < max_softdeps_hard / 2 &&
num_inodedep < max_softdeps_hard &&
- VFSTOUFS(vp->v_mount)->um_numindirdeps < maxindirdeps) {
+ VFSTOUFS(vp->v_mount)->um_numindirdeps < maxindirdeps &&
+ num_freeblkdep < max_softdeps_hard) {
FREE_LOCK(&lk);
return (0);
}
@@ -5950,12 +5977,19 @@ clear_remove(td)
if (vn_start_write(NULL, &mp, V_NOWAIT) != 0)
continue;
FREE_LOCK(&lk);
- if ((error = ffs_vgetf(mp, ino, LK_EXCLUSIVE, &vp,
- FFSV_FORCEINSMQ))) {
+
+ /*
+ * Let unmount clear deps
+ */
+ error = vfs_busy(mp, MBF_NOWAIT);
+ if (error != 0)
+ goto finish_write;
+ error = ffs_vgetf(mp, ino, LK_EXCLUSIVE, &vp,
+ FFSV_FORCEINSMQ);
+ vfs_unbusy(mp);
+ if (error != 0) {
softdep_error("clear_remove: vget", error);
- vn_finished_write(mp);
- ACQUIRE_LOCK(&lk);
- return;
+ goto finish_write;
}
if ((error = ffs_syncvnode(vp, MNT_NOWAIT)))
softdep_error("clear_remove: fsync", error);
@@ -5964,6 +5998,7 @@ clear_remove(td)
drain_output(vp);
BO_UNLOCK(bo);
vput(vp);
+ finish_write:
vn_finished_write(mp);
ACQUIRE_LOCK(&lk);
return;
@@ -6023,13 +6058,21 @@ clear_inodedeps(td)
if (vn_start_write(NULL, &mp, V_NOWAIT) != 0)
continue;
FREE_LOCK(&lk);
+ error = vfs_busy(mp, MBF_NOWAIT); /* Let unmount clear deps */
+ if (error != 0) {
+ vn_finished_write(mp);
+ ACQUIRE_LOCK(&lk);
+ return;
+ }
if ((error = ffs_vgetf(mp, ino, LK_EXCLUSIVE, &vp,
FFSV_FORCEINSMQ)) != 0) {
softdep_error("clear_inodedeps: vget", error);
+ vfs_unbusy(mp);
vn_finished_write(mp);
ACQUIRE_LOCK(&lk);
return;
}
+ vfs_unbusy(mp);
if (ino == lastino) {
if ((error = ffs_syncvnode(vp, MNT_WAIT)))
softdep_error("clear_inodedeps: fsync1", error);
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
index 95dbeb1f0989..d3d7c2c60730 100644
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -32,7 +32,6 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include "opt_mac.h"
#include "opt_quota.h"
#include "opt_ufs.h"
#include "opt_ffs.h"
@@ -132,9 +131,10 @@ static const char *ffs_opts[] = { "acls", "async", "noatime", "noclusterr",
"union", NULL };
static int
-ffs_mount(struct mount *mp, struct thread *td)
+ffs_mount(struct mount *mp)
{
struct vnode *devvp;
+ struct thread *td;
struct ufsmount *ump = 0;
struct fs *fs;
int error, flags;
@@ -143,6 +143,7 @@ ffs_mount(struct mount *mp, struct thread *td)
struct nameidata ndp;
char *fspec;
+ td = curthread;
if (vfs_filteropt(mp->mnt_optnew, ffs_opts))
return (EINVAL);
if (uma_inode == NULL) {
@@ -213,7 +214,7 @@ ffs_mount(struct mount *mp, struct thread *td)
* ignore the suspension to
* synchronize on-disk state.
*/
- curthread->td_pflags |= TDP_IGNSUSP;
+ td->td_pflags |= TDP_IGNSUSP;
break;
}
MNT_IUNLOCK(mp);
@@ -431,7 +432,7 @@ ffs_mount(struct mount *mp, struct thread *td)
*/
static int
-ffs_cmount(struct mntarg *ma, void *data, int flags, struct thread *td)
+ffs_cmount(struct mntarg *ma, void *data, int flags)
{
struct ufs_args args;
int error;
@@ -883,7 +884,8 @@ ffs_mountfs(devvp, mp, td)
* Initialize filesystem stat information in mount struct.
*/
MNT_ILOCK(mp);
- mp->mnt_kern_flag |= MNTK_MPSAFE | MNTK_LOOKUP_SHARED;
+ mp->mnt_kern_flag |= MNTK_MPSAFE | MNTK_LOOKUP_SHARED |
+ MNTK_EXTENDED_SHARED;
MNT_IUNLOCK(mp);
#ifdef UFS_EXTATTR
#ifdef UFS_EXTATTR_AUTOSTART
@@ -1024,11 +1026,11 @@ ffs_oldfscompat_write(fs, ump)
* unmount system call
*/
static int
-ffs_unmount(mp, mntflags, td)
+ffs_unmount(mp, mntflags)
struct mount *mp;
int mntflags;
- struct thread *td;
{
+ struct thread *td;
struct ufsmount *ump = VFSTOUFS(mp);
struct fs *fs;
int error, flags, susp;
@@ -1037,6 +1039,7 @@ ffs_unmount(mp, mntflags, td)
#endif
flags = 0;
+ td = curthread;
fs = ump->um_fs;
if (mntflags & MNT_FORCE) {
flags |= FORCECLOSE;
@@ -1068,20 +1071,20 @@ ffs_unmount(mp, mntflags, td)
MNTK_SUSPEND2);
wakeup(&mp->mnt_flag);
MNT_IUNLOCK(mp);
- curthread->td_pflags |= TDP_IGNSUSP;
+ td->td_pflags |= TDP_IGNSUSP;
break;
}
MNT_IUNLOCK(mp);
vn_start_write(NULL, &mp, V_WAIT);
}
}
- if (mp->mnt_flag & MNT_SOFTDEP) {
- if ((error = softdep_flushfiles(mp, flags, td)) != 0)
- goto fail;
- } else {
- if ((error = ffs_flushfiles(mp, flags, td)) != 0)
- goto fail;
- }
+ if (mp->mnt_flag & MNT_SOFTDEP)
+ error = softdep_flushfiles(mp, flags, td);
+ else
+ error = ffs_flushfiles(mp, flags, td);
+ if (error != 0 && error != ENXIO)
+ goto fail;
+
UFS_LOCK(ump);
if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
printf("%s: unmount pending error: blocks %jd files %d\n",
@@ -1094,7 +1097,7 @@ ffs_unmount(mp, mntflags, td)
if (fs->fs_ronly == 0) {
fs->fs_clean = fs->fs_flags & (FS_UNCLEAN|FS_NEEDSFSCK) ? 0 : 1;
error = ffs_sbupdate(ump, MNT_WAIT, 0);
- if (error) {
+ if (error && error != ENXIO) {
fs->fs_clean = 0;
goto fail;
}
@@ -1198,10 +1201,9 @@ ffs_flushfiles(mp, flags, td)
* Get filesystem statistics.
*/
static int
-ffs_statfs(mp, sbp, td)
+ffs_statfs(mp, sbp)
struct mount *mp;
struct statfs *sbp;
- struct thread *td;
{
struct ufsmount *ump;
struct fs *fs;
@@ -1234,12 +1236,12 @@ ffs_statfs(mp, sbp, td)
* Note: we are always called with the filesystem marked `MPBUSY'.
*/
static int
-ffs_sync(mp, waitfor, td)
+ffs_sync(mp, waitfor)
struct mount *mp;
int waitfor;
- struct thread *td;
{
struct vnode *mvp, *vp, *devvp;
+ struct thread *td;
struct inode *ip;
struct ufsmount *ump = VFSTOUFS(mp);
struct fs *fs;
@@ -1252,6 +1254,7 @@ ffs_sync(mp, waitfor, td)
int softdep_accdeps;
struct bufobj *bo;
+ td = curthread;
fs = ump->um_fs;
if (fs->fs_fmod != 0 && fs->fs_ronly != 0) { /* XXX */
printf("fs = %s\n", fs->fs_fsmnt);
@@ -1440,10 +1443,9 @@ ffs_vgetf(mp, ino, flags, vpp, ffs_flags)
return (error);
}
/*
- * FFS supports recursive and shared locking.
+ * FFS supports recursive locking.
*/
VN_LOCK_AREC(vp);
- VN_LOCK_ASHARE(vp);
vp->v_data = ip;
vp->v_bufobj.bo_bsize = fs->fs_bsize;
ip->i_vnode = vp;
@@ -1451,6 +1453,7 @@ ffs_vgetf(mp, ino, flags, vpp, ffs_flags)
ip->i_fs = fs;
ip->i_dev = dev;
ip->i_number = ino;
+ ip->i_ea_refs = 0;
#ifdef QUOTA
{
int i;
@@ -1516,6 +1519,10 @@ ffs_vgetf(mp, ino, flags, vpp, ffs_flags)
/*
* Finish inode initialization.
*/
+ if (vp->v_type != VFIFO) {
+ /* FFS supports shared locking for all files except fifos. */
+ VN_LOCK_ASHARE(vp);
+ }
/*
* Set up a generation number for this inode if it does not
@@ -1694,15 +1701,15 @@ ffs_sbupdate(mp, waitfor, suspended)
static int
ffs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp,
- int attrnamespace, const char *attrname, struct thread *td)
+ int attrnamespace, const char *attrname)
{
#ifdef UFS_EXTATTR
return (ufs_extattrctl(mp, cmd, filename_vp, attrnamespace,
- attrname, td));
+ attrname));
#else
return (vfs_stdextattrctl(mp, cmd, filename_vp, attrnamespace,
- attrname, td));
+ attrname));
#endif
}
@@ -1841,7 +1848,9 @@ ffs_bufwrite(struct buf *bp)
("bufwrite: needs chained iodone (%p)", bp->b_iodone));
/* get a new block */
- newbp = geteblk(bp->b_bufsize);
+ newbp = geteblk(bp->b_bufsize, GB_NOWAIT_BD);
+ if (newbp == NULL)
+ goto normal_write;
/*
* set it to be identical to the old block. We have to
@@ -1881,6 +1890,7 @@ ffs_bufwrite(struct buf *bp)
}
/* Let the normal bufwrite do the rest for us */
+normal_write:
return (bufwrite(bp));
}
@@ -1915,7 +1925,7 @@ ffs_geom_strategy(struct bufobj *bo, struct buf *bp)
}
}
bp->b_runningbufspace = bp->b_bufsize;
- atomic_add_int(&runningbufspace,
+ atomic_add_long(&runningbufspace,
bp->b_runningbufspace);
} else {
error = ffs_copyonwrite(vp, bp);
diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c
index ca2efa619033..464a7613e162 100644
--- a/sys/ufs/ffs/ffs_vnops.c
+++ b/sys/ufs/ffs/ffs_vnops.c
@@ -180,15 +180,36 @@ struct vop_vector ffs_fifoops2 = {
static int
ffs_fsync(struct vop_fsync_args *ap)
{
+ struct vnode *vp;
+ struct bufobj *bo;
int error;
- error = ffs_syncvnode(ap->a_vp, ap->a_waitfor);
+ vp = ap->a_vp;
+ bo = &vp->v_bufobj;
+retry:
+ error = ffs_syncvnode(vp, ap->a_waitfor);
if (error)
return (error);
if (ap->a_waitfor == MNT_WAIT &&
- (ap->a_vp->v_mount->mnt_flag & MNT_SOFTDEP))
- error = softdep_fsync(ap->a_vp);
- return (error);
+ (vp->v_mount->mnt_flag & MNT_SOFTDEP)) {
+ error = softdep_fsync(vp);
+ if (error)
+ return (error);
+
+ /*
+ * The softdep_fsync() function may drop vp lock,
+ * allowing for dirty buffers to reappear on the
+ * bo_dirty list. Recheck and resync as needed.
+ */
+ BO_LOCK(bo);
+ if (vp->v_type == VREG && (bo->bo_numoutput > 0 ||
+ bo->bo_dirty.bv_cnt > 0)) {
+ BO_UNLOCK(bo);
+ goto retry;
+ }
+ BO_UNLOCK(bo);
+ }
+ return (0);
}
int
@@ -1225,6 +1246,35 @@ ffs_rdextattr(u_char **p, struct vnode *vp, struct thread *td, int extra)
return (0);
}
+static void
+ffs_lock_ea(struct vnode *vp)
+{
+ struct inode *ip;
+
+ ip = VTOI(vp);
+ VI_LOCK(vp);
+ while (ip->i_flag & IN_EA_LOCKED) {
+ ip->i_flag |= IN_EA_LOCKWAIT;
+ msleep(&ip->i_ea_refs, &vp->v_interlock, PINOD + 2, "ufs_ea",
+ 0);
+ }
+ ip->i_flag |= IN_EA_LOCKED;
+ VI_UNLOCK(vp);
+}
+
+static void
+ffs_unlock_ea(struct vnode *vp)
+{
+ struct inode *ip;
+
+ ip = VTOI(vp);
+ VI_LOCK(vp);
+ if (ip->i_flag & IN_EA_LOCKWAIT)
+ wakeup(&ip->i_ea_refs);
+ ip->i_flag &= ~(IN_EA_LOCKED | IN_EA_LOCKWAIT);
+ VI_UNLOCK(vp);
+}
+
static int
ffs_open_ea(struct vnode *vp, struct ucred *cred, struct thread *td)
{
@@ -1234,14 +1284,22 @@ ffs_open_ea(struct vnode *vp, struct ucred *cred, struct thread *td)
ip = VTOI(vp);
- if (ip->i_ea_area != NULL)
- return (EBUSY);
+ ffs_lock_ea(vp);
+ if (ip->i_ea_area != NULL) {
+ ip->i_ea_refs++;
+ ffs_unlock_ea(vp);
+ return (0);
+ }
dp = ip->i_din2;
error = ffs_rdextattr(&ip->i_ea_area, vp, td, 0);
- if (error)
+ if (error) {
+ ffs_unlock_ea(vp);
return (error);
+ }
ip->i_ea_len = dp->di_extsize;
ip->i_ea_error = 0;
+ ip->i_ea_refs++;
+ ffs_unlock_ea(vp);
return (0);
}
@@ -1258,11 +1316,16 @@ ffs_close_ea(struct vnode *vp, int commit, struct ucred *cred, struct thread *td
struct ufs2_dinode *dp;
ip = VTOI(vp);
- if (ip->i_ea_area == NULL)
+
+ ffs_lock_ea(vp);
+ if (ip->i_ea_area == NULL) {
+ ffs_unlock_ea(vp);
return (EINVAL);
+ }
dp = ip->i_din2;
error = ip->i_ea_error;
if (commit && error == 0) {
+ ASSERT_VOP_ELOCKED(vp, "ffs_close_ea commit");
if (cred == NOCRED)
cred = vp->v_mount->mnt_cred;
liovec.iov_base = ip->i_ea_area;
@@ -1279,10 +1342,13 @@ ffs_close_ea(struct vnode *vp, int commit, struct ucred *cred, struct thread *td
error = ffs_truncate(vp, 0, IO_EXT, cred, td);
error = ffs_extwrite(vp, &luio, IO_EXT | IO_SYNC, cred);
}
- free(ip->i_ea_area, M_TEMP);
- ip->i_ea_area = NULL;
- ip->i_ea_len = 0;
- ip->i_ea_error = 0;
+ if (--ip->i_ea_refs == 0) {
+ free(ip->i_ea_area, M_TEMP);
+ ip->i_ea_area = NULL;
+ ip->i_ea_len = 0;
+ ip->i_ea_error = 0;
+ }
+ ffs_unlock_ea(vp);
return (error);
}
@@ -1335,7 +1401,7 @@ struct vop_openextattr_args {
ip = VTOI(ap->a_vp);
fs = ip->i_fs;
- if (ap->a_vp->v_type == VCHR)
+ if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK)
return (EOPNOTSUPP);
return (ffs_open_ea(ap->a_vp, ap->a_cred, ap->a_td));
@@ -1363,7 +1429,7 @@ struct vop_closeextattr_args {
ip = VTOI(ap->a_vp);
fs = ip->i_fs;
- if (ap->a_vp->v_type == VCHR)
+ if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK)
return (EOPNOTSUPP);
if (ap->a_commit && (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY))
@@ -1392,12 +1458,11 @@ vop_deleteextattr {
uint32_t ealength, ul;
int ealen, olen, eapad1, eapad2, error, i, easize;
u_char *eae, *p;
- int stand_alone;
ip = VTOI(ap->a_vp);
fs = ip->i_fs;
- if (ap->a_vp->v_type == VCHR)
+ if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK)
return (EOPNOTSUPP);
if (strlen(ap->a_name) == 0)
@@ -1409,19 +1474,19 @@ vop_deleteextattr {
error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
ap->a_cred, ap->a_td, VWRITE);
if (error) {
+
+ /*
+ * ffs_lock_ea is not needed there, because the vnode
+ * must be exclusively locked.
+ */
if (ip->i_ea_area != NULL && ip->i_ea_error == 0)
ip->i_ea_error = error;
return (error);
}
- if (ip->i_ea_area == NULL) {
- error = ffs_open_ea(ap->a_vp, ap->a_cred, ap->a_td);
- if (error)
- return (error);
- stand_alone = 1;
- } else {
- stand_alone = 0;
- }
+ error = ffs_open_ea(ap->a_vp, ap->a_cred, ap->a_td);
+ if (error)
+ return (error);
ealength = eapad1 = ealen = eapad2 = 0;
@@ -1434,8 +1499,7 @@ vop_deleteextattr {
if (olen == -1) {
/* delete but nonexistent */
free(eae, M_TEMP);
- if (stand_alone)
- ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td);
+ ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td);
return(ENOATTR);
}
bcopy(p, &ul, sizeof ul);
@@ -1446,9 +1510,8 @@ vop_deleteextattr {
}
if (easize > NXADDR * fs->fs_bsize) {
free(eae, M_TEMP);
- if (stand_alone)
- ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td);
- else if (ip->i_ea_error == 0)
+ ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td);
+ if (ip->i_ea_area != NULL && ip->i_ea_error == 0)
ip->i_ea_error = ENOSPC;
return(ENOSPC);
}
@@ -1456,8 +1519,7 @@ vop_deleteextattr {
ip->i_ea_area = eae;
ip->i_ea_len = easize;
free(p, M_TEMP);
- if (stand_alone)
- error = ffs_close_ea(ap->a_vp, 1, ap->a_cred, ap->a_td);
+ error = ffs_close_ea(ap->a_vp, 1, ap->a_cred, ap->a_td);
return(error);
}
@@ -1482,12 +1544,12 @@ vop_getextattr {
struct fs *fs;
u_char *eae, *p;
unsigned easize;
- int error, ealen, stand_alone;
+ int error, ealen;
ip = VTOI(ap->a_vp);
fs = ip->i_fs;
- if (ap->a_vp->v_type == VCHR)
+ if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK)
return (EOPNOTSUPP);
error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
@@ -1495,14 +1557,10 @@ vop_getextattr {
if (error)
return (error);
- if (ip->i_ea_area == NULL) {
- error = ffs_open_ea(ap->a_vp, ap->a_cred, ap->a_td);
- if (error)
- return (error);
- stand_alone = 1;
- } else {
- stand_alone = 0;
- }
+ error = ffs_open_ea(ap->a_vp, ap->a_cred, ap->a_td);
+ if (error)
+ return (error);
+
eae = ip->i_ea_area;
easize = ip->i_ea_len;
@@ -1516,8 +1574,8 @@ vop_getextattr {
error = uiomove(p, ealen, ap->a_uio);
} else
error = ENOATTR;
- if (stand_alone)
- ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td);
+
+ ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td);
return(error);
}
@@ -1542,12 +1600,12 @@ vop_listextattr {
u_char *eae, *p, *pe, *pn;
unsigned easize;
uint32_t ul;
- int error, ealen, stand_alone;
+ int error, ealen;
ip = VTOI(ap->a_vp);
fs = ip->i_fs;
- if (ap->a_vp->v_type == VCHR)
+ if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK)
return (EOPNOTSUPP);
error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
@@ -1555,14 +1613,9 @@ vop_listextattr {
if (error)
return (error);
- if (ip->i_ea_area == NULL) {
- error = ffs_open_ea(ap->a_vp, ap->a_cred, ap->a_td);
- if (error)
- return (error);
- stand_alone = 1;
- } else {
- stand_alone = 0;
- }
+ error = ffs_open_ea(ap->a_vp, ap->a_cred, ap->a_td);
+ if (error)
+ return (error);
eae = ip->i_ea_area;
easize = ip->i_ea_len;
@@ -1586,8 +1639,7 @@ vop_listextattr {
error = uiomove(p, ealen + 1, ap->a_uio);
}
}
- if (stand_alone)
- ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td);
+ ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td);
return(error);
}
@@ -1612,12 +1664,11 @@ vop_setextattr {
uint32_t ealength, ul;
int ealen, olen, eapad1, eapad2, error, i, easize;
u_char *eae, *p;
- int stand_alone;
ip = VTOI(ap->a_vp);
fs = ip->i_fs;
- if (ap->a_vp->v_type == VCHR)
+ if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK)
return (EOPNOTSUPP);
if (strlen(ap->a_name) == 0)
@@ -1633,19 +1684,19 @@ vop_setextattr {
error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
ap->a_cred, ap->a_td, VWRITE);
if (error) {
+
+ /*
+ * ffs_lock_ea is not needed there, because the vnode
+ * must be exclusively locked.
+ */
if (ip->i_ea_area != NULL && ip->i_ea_error == 0)
ip->i_ea_error = error;
return (error);
}
- if (ip->i_ea_area == NULL) {
- error = ffs_open_ea(ap->a_vp, ap->a_cred, ap->a_td);
- if (error)
- return (error);
- stand_alone = 1;
- } else {
- stand_alone = 0;
- }
+ error = ffs_open_ea(ap->a_vp, ap->a_cred, ap->a_td);
+ if (error)
+ return (error);
ealen = ap->a_uio->uio_resid;
ealength = sizeof(uint32_t) + 3 + strlen(ap->a_name);
@@ -1677,9 +1728,8 @@ vop_setextattr {
}
if (easize > NXADDR * fs->fs_bsize) {
free(eae, M_TEMP);
- if (stand_alone)
- ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td);
- else if (ip->i_ea_error == 0)
+ ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td);
+ if (ip->i_ea_area != NULL && ip->i_ea_error == 0)
ip->i_ea_error = ENOSPC;
return(ENOSPC);
}
@@ -1695,9 +1745,8 @@ vop_setextattr {
error = uiomove(p, ealen, ap->a_uio);
if (error) {
free(eae, M_TEMP);
- if (stand_alone)
- ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td);
- else if (ip->i_ea_error == 0)
+ ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td);
+ if (ip->i_ea_area != NULL && ip->i_ea_error == 0)
ip->i_ea_error = error;
return(error);
}
@@ -1708,8 +1757,7 @@ vop_setextattr {
ip->i_ea_area = eae;
ip->i_ea_len = easize;
free(p, M_TEMP);
- if (stand_alone)
- error = ffs_close_ea(ap->a_vp, 1, ap->a_cred, ap->a_td);
+ error = ffs_close_ea(ap->a_vp, 1, ap->a_cred, ap->a_td);
return(error);
}
diff --git a/sys/ufs/ufs/dinode.h b/sys/ufs/ufs/dinode.h
index aba4348b4b3d..7f9e7c56496e 100644
--- a/sys/ufs/ufs/dinode.h
+++ b/sys/ufs/ufs/dinode.h
@@ -145,7 +145,8 @@ struct ufs2_dinode {
ufs2_daddr_t di_extb[NXADDR];/* 96: External attributes block. */
ufs2_daddr_t di_db[NDADDR]; /* 112: Direct disk blocks. */
ufs2_daddr_t di_ib[NIADDR]; /* 208: Indirect disk blocks. */
- int64_t di_spare[3]; /* 232: Reserved; currently unused */
+ u_int64_t di_modrev; /* 232: i_modrev for NFSv4 */
+ int64_t di_spare[2]; /* 240: Reserved; currently unused */
};
/*
@@ -183,7 +184,7 @@ struct ufs1_dinode {
int32_t di_gen; /* 108: Generation number. */
u_int32_t di_uid; /* 112: File owner. */
u_int32_t di_gid; /* 116: File group. */
- int32_t di_spare[2]; /* 120: Reserved; currently unused */
+ u_int64_t di_modrev; /* 120: i_modrev for NFSv4 */
};
#define di_ogid di_u.oldids[1]
#define di_ouid di_u.oldids[0]
diff --git a/sys/ufs/ufs/dirhash.h b/sys/ufs/ufs/dirhash.h
index 9778752a5f50..e5978b411d94 100644
--- a/sys/ufs/ufs/dirhash.h
+++ b/sys/ufs/ufs/dirhash.h
@@ -105,6 +105,8 @@ struct dirhash {
int dh_onlist; /* true if on the ufsdirhash_list chain */
+ time_t dh_lastused; /* time the dirhash was last read or written*/
+
/* Protected by ufsdirhash_mtx. */
TAILQ_ENTRY(dirhash) dh_list; /* chain of all dirhashes */
};
diff --git a/sys/ufs/ufs/extattr.h b/sys/ufs/ufs/extattr.h
index 5d26bf6cd552..3716ec27309a 100644
--- a/sys/ufs/ufs/extattr.h
+++ b/sys/ufs/ufs/extattr.h
@@ -143,7 +143,7 @@ int ufs_extattr_start(struct mount *mp, struct thread *td);
int ufs_extattr_autostart(struct mount *mp, struct thread *td);
int ufs_extattr_stop(struct mount *mp, struct thread *td);
int ufs_extattrctl(struct mount *mp, int cmd, struct vnode *filename,
- int attrnamespace, const char *attrname, struct thread *td);
+ int attrnamespace, const char *attrname);
int ufs_getextattr(struct vop_getextattr_args *ap);
int ufs_deleteextattr(struct vop_deleteextattr_args *ap);
int ufs_setextattr(struct vop_setextattr_args *ap);
diff --git a/sys/ufs/ufs/inode.h b/sys/ufs/ufs/inode.h
index 39f46d0aea73..565580e60460 100644
--- a/sys/ufs/ufs/inode.h
+++ b/sys/ufs/ufs/inode.h
@@ -74,7 +74,6 @@ struct inode {
struct fs *i_fs; /* Associated filesystem superblock. */
struct dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */
- u_quad_t i_modrev; /* Revision level for NFS lease. */
/*
* Side effects; used during directory lookup.
*/
@@ -94,6 +93,7 @@ struct inode {
u_char *i_ea_area; /* Pointer to malloced copy of EA area */
unsigned i_ea_len; /* Length of i_ea_area */
int i_ea_error; /* First errno in transaction */
+ int i_ea_refs; /* Number of users of EA area */
/*
* Copies from the on-disk dinode itself.
@@ -125,6 +125,8 @@ struct inode {
#define IN_SPACECOUNTED 0x0080 /* Blocks to be freed in free count. */
#define IN_LAZYACCESS 0x0100 /* Process IN_ACCESS after the
suspension finished */
+#define IN_EA_LOCKED 0x0200
+#define IN_EA_LOCKWAIT 0x0400
#define i_devvp i_ump->um_devvp
#define i_umbufobj i_ump->um_bo
diff --git a/sys/ufs/ufs/ufs_acl.c b/sys/ufs/ufs/ufs_acl.c
index 89488c7995fb..68e5015c2d4e 100644
--- a/sys/ufs/ufs/ufs_acl.c
+++ b/sys/ufs/ufs/ufs_acl.c
@@ -141,24 +141,68 @@ ufs_sync_inode_from_acl(struct acl *acl, struct inode *ip)
}
/*
+ * Read POSIX.1e ACL from an EA. Return error if its not found
+ * or if any other error has occured.
+ */
+static int
+ufs_get_oldacl(acl_type_t type, struct oldacl *old, struct vnode *vp,
+ struct thread *td)
+{
+ int error, len;
+ struct inode *ip = VTOI(vp);
+
+ len = sizeof(*old);
+
+ switch (type) {
+ case ACL_TYPE_ACCESS:
+ error = vn_extattr_get(vp, IO_NODELOCKED,
+ POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE,
+ POSIX1E_ACL_ACCESS_EXTATTR_NAME, &len, (char *) old,
+ td);
+ break;
+ case ACL_TYPE_DEFAULT:
+ if (vp->v_type != VDIR)
+ return (EINVAL);
+ error = vn_extattr_get(vp, IO_NODELOCKED,
+ POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE,
+ POSIX1E_ACL_DEFAULT_EXTATTR_NAME, &len, (char *) old,
+ td);
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ if (error != 0)
+ return (error);
+
+ if (len != sizeof(*old)) {
+ /*
+ * A short (or long) read, meaning that for some reason
+ * the ACL is corrupted. Return EPERM since the object
+ * DAC protections are unsafe.
+ */
+ printf("ufs_get_oldacl(): Loaded invalid ACL "
+ "(len = %d), inumber %d on %s\n", len,
+ ip->i_number, ip->i_fs->fs_fsmnt);
+ return (EPERM);
+ }
+
+ return (0);
+}
+
+/*
* Retrieve the ACL on a file.
*
* As part of the ACL is stored in the inode, and the rest in an EA,
* assemble both into a final ACL product. Right now this is not done
* very efficiently.
*/
-int
-ufs_getacl(ap)
- struct vop_getacl_args /* {
- struct vnode *vp;
- struct acl_type_t type;
- struct acl *aclp;
- struct ucred *cred;
- struct thread *td;
- } */ *ap;
+static int
+ufs_getacl_posix1e(struct vop_getacl_args *ap)
{
struct inode *ip = VTOI(ap->a_vp);
- int error, len;
+ int error;
+ struct oldacl *old;
/*
* XXX: If ufs_getacl() should work on file systems not supporting
@@ -167,121 +211,80 @@ ufs_getacl(ap)
if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0)
return (EOPNOTSUPP);
+ old = malloc(sizeof(*old), M_ACL, M_WAITOK | M_ZERO);
+
/*
- * Attempt to retrieve the ACL based on the ACL type.
+ * Attempt to retrieve the ACL from the extended attributes.
*/
- bzero(ap->a_aclp, sizeof(*ap->a_aclp));
- len = sizeof(*ap->a_aclp);
- switch(ap->a_type) {
- case ACL_TYPE_ACCESS:
- /*
- * ACL_TYPE_ACCESS ACLs may or may not be stored in the
- * EA, as they are in fact a combination of the inode
- * ownership/permissions and the EA contents. If the
- * EA is present, merge the two in a temporary ACL
- * storage, otherwise just return the inode contents.
- */
- error = vn_extattr_get(ap->a_vp, IO_NODELOCKED,
- POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE,
- POSIX1E_ACL_ACCESS_EXTATTR_NAME, &len, (char *) ap->a_aclp,
- ap->a_td);
- switch (error) {
- /* XXX: If ufs_getacl() should work on filesystems without
- * the EA configured, add case EOPNOTSUPP here. */
- case ENOATTR:
+ error = ufs_get_oldacl(ap->a_type, old, ap->a_vp, ap->a_td);
+ switch (error) {
+ /*
+ * XXX: If ufs_getacl() should work on filesystems
+ * without the EA configured, add case EOPNOTSUPP here.
+ */
+ case ENOATTR:
+ switch (ap->a_type) {
+ case ACL_TYPE_ACCESS:
/*
* Legitimately no ACL set on object, purely
* emulate it through the inode. These fields will
* be updated when the ACL is synchronized with
* the inode later.
*/
- ap->a_aclp->acl_cnt = 3;
- ap->a_aclp->acl_entry[0].ae_tag = ACL_USER_OBJ;
- ap->a_aclp->acl_entry[0].ae_id = ACL_UNDEFINED_ID;
- ap->a_aclp->acl_entry[0].ae_perm = ACL_PERM_NONE;
- ap->a_aclp->acl_entry[1].ae_tag = ACL_GROUP_OBJ;
- ap->a_aclp->acl_entry[1].ae_id = ACL_UNDEFINED_ID;
- ap->a_aclp->acl_entry[1].ae_perm = ACL_PERM_NONE;
- ap->a_aclp->acl_entry[2].ae_tag = ACL_OTHER;
- ap->a_aclp->acl_entry[2].ae_id = ACL_UNDEFINED_ID;
- ap->a_aclp->acl_entry[2].ae_perm = ACL_PERM_NONE;
- ufs_sync_acl_from_inode(ip, ap->a_aclp);
- error = 0;
+ old->acl_cnt = 3;
+ old->acl_entry[0].ae_tag = ACL_USER_OBJ;
+ old->acl_entry[0].ae_id = ACL_UNDEFINED_ID;
+ old->acl_entry[0].ae_perm = ACL_PERM_NONE;
+ old->acl_entry[1].ae_tag = ACL_GROUP_OBJ;
+ old->acl_entry[1].ae_id = ACL_UNDEFINED_ID;
+ old->acl_entry[1].ae_perm = ACL_PERM_NONE;
+ old->acl_entry[2].ae_tag = ACL_OTHER;
+ old->acl_entry[2].ae_id = ACL_UNDEFINED_ID;
+ old->acl_entry[2].ae_perm = ACL_PERM_NONE;
break;
- case 0:
- if (len != sizeof(*ap->a_aclp)) {
- /*
- * A short (or long) read, meaning that for
- * some reason the ACL is corrupted. Return
- * EPERM since the object DAC protections
- * are unsafe.
- */
- printf("ufs_getacl(): Loaded invalid ACL ("
- "%d bytes), inumber %d on %s\n", len,
- ip->i_number, ip->i_fs->fs_fsmnt);
- return (EPERM);
- }
- ufs_sync_acl_from_inode(ip, ap->a_aclp);
- break;
-
- default:
- break;
- }
- break;
-
- case ACL_TYPE_DEFAULT:
- if (ap->a_vp->v_type != VDIR) {
- error = EINVAL;
+ case ACL_TYPE_DEFAULT:
+ /*
+ * Unlike ACL_TYPE_ACCESS, there is no relationship
+ * between the inode contents and the ACL, and it is
+ * therefore possible for the request for the ACL
+ * to fail since the ACL is undefined. In this
+ * situation, return success and an empty ACL,
+ * as required by POSIX.1e.
+ */
+ old->acl_cnt = 0;
break;
}
- error = vn_extattr_get(ap->a_vp, IO_NODELOCKED,
- POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE,
- POSIX1E_ACL_DEFAULT_EXTATTR_NAME, &len,
- (char *) ap->a_aclp, ap->a_td);
- /*
- * Unlike ACL_TYPE_ACCESS, there is no relationship between
- * the inode contents and the ACL, and it is therefore
- * possible for the request for the ACL to fail since the
- * ACL is undefined. In this situation, return success
- * and an empty ACL, as required by POSIX.1e.
- */
- switch (error) {
- /* XXX: If ufs_getacl() should work on filesystems without
- * the EA configured, add case EOPNOTSUPP here. */
- case ENOATTR:
- bzero(ap->a_aclp, sizeof(*ap->a_aclp));
- ap->a_aclp->acl_cnt = 0;
- error = 0;
- break;
-
- case 0:
- if (len != sizeof(*ap->a_aclp)) {
- /*
- * A short (or long) read, meaning that for
- * some reason the ACL is corrupted. Return
- * EPERM since the object default DAC
- * protections are unsafe.
- */
- printf("ufs_getacl(): Loaded invalid ACL ("
- "%d bytes), inumber %d on %s\n", len,
- ip->i_number, ip->i_fs->fs_fsmnt);
- return (EPERM);
- }
- break;
-
- default:
+ /* FALLTHROUGH */
+ case 0:
+ error = acl_copy_oldacl_into_acl(old, ap->a_aclp);
+ if (error != 0)
break;
- }
- break;
+ if (ap->a_type == ACL_TYPE_ACCESS)
+ ufs_sync_acl_from_inode(ip, ap->a_aclp);
default:
- error = EINVAL;
+ break;
}
+ free(old, M_ACL);
return (error);
}
+int
+ufs_getacl(ap)
+ struct vop_getacl_args /* {
+ struct vnode *vp;
+ acl_type_t type;
+ struct acl *aclp;
+ struct ucred *cred;
+ struct thread *td;
+ } */ *ap;
+{
+
+ return (ufs_getacl_posix1e(ap));
+}
+
/*
* Set the ACL on a file.
*
@@ -291,18 +294,12 @@ ufs_getacl(ap)
* a fair number of different access checks may be required to go ahead
* with the operation at all.
*/
-int
-ufs_setacl(ap)
- struct vop_setacl_args /* {
- struct vnode *vp;
- acl_type_t type;
- struct acl *aclp;
- struct ucred *cred;
- struct proc *p;
- } */ *ap;
+static int
+ufs_setacl_posix1e(struct vop_setacl_args *ap)
{
struct inode *ip = VTOI(ap->a_vp);
int error;
+ struct oldacl *old;
if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0)
return (EOPNOTSUPP);
@@ -349,10 +346,15 @@ ufs_setacl(ap)
switch(ap->a_type) {
case ACL_TYPE_ACCESS:
- error = vn_extattr_set(ap->a_vp, IO_NODELOCKED,
- POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE,
- POSIX1E_ACL_ACCESS_EXTATTR_NAME, sizeof(*ap->a_aclp),
- (char *) ap->a_aclp, ap->a_td);
+ old = malloc(sizeof(*old), M_ACL, M_WAITOK | M_ZERO);
+ error = acl_copy_acl_into_oldacl(ap->a_aclp, old);
+ if (error == 0) {
+ error = vn_extattr_set(ap->a_vp, IO_NODELOCKED,
+ POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE,
+ POSIX1E_ACL_ACCESS_EXTATTR_NAME, sizeof(*old),
+ (char *) old, ap->a_td);
+ }
+ free(old, M_ACL);
break;
case ACL_TYPE_DEFAULT:
@@ -372,11 +374,17 @@ ufs_setacl(ap)
*/
if (error == ENOATTR)
error = 0;
- } else
- error = vn_extattr_set(ap->a_vp, IO_NODELOCKED,
- POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE,
- POSIX1E_ACL_DEFAULT_EXTATTR_NAME,
- sizeof(*ap->a_aclp), (char *) ap->a_aclp, ap->a_td);
+ } else {
+ old = malloc(sizeof(*old), M_ACL, M_WAITOK | M_ZERO);
+ error = acl_copy_acl_into_oldacl(ap->a_aclp, old);
+ if (error == 0) {
+ error = vn_extattr_set(ap->a_vp, IO_NODELOCKED,
+ POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE,
+ POSIX1E_ACL_DEFAULT_EXTATTR_NAME,
+ sizeof(*old), (char *) old, ap->a_td);
+ }
+ free(old, M_ACL);
+ }
break;
default:
@@ -404,12 +412,9 @@ ufs_setacl(ap)
return (0);
}
-/*
- * Check the validity of an ACL for a file.
- */
int
-ufs_aclcheck(ap)
- struct vop_aclcheck_args /* {
+ufs_setacl(ap)
+ struct vop_setacl_args /* {
struct vnode *vp;
acl_type_t type;
struct acl *aclp;
@@ -418,6 +423,13 @@ ufs_aclcheck(ap)
} */ *ap;
{
+ return (ufs_setacl_posix1e(ap));
+}
+
+static int
+ufs_aclcheck_posix1e(struct vop_aclcheck_args *ap)
+{
+
if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0)
return (EOPNOTSUPP);
@@ -438,7 +450,28 @@ ufs_aclcheck(ap)
default:
return (EINVAL);
}
+
+ if (ap->a_aclp->acl_cnt > OLDACL_MAX_ENTRIES)
+ return (EINVAL);
+
return (acl_posix1e_check(ap->a_aclp));
}
+/*
+ * Check the validity of an ACL for a file.
+ */
+int
+ufs_aclcheck(ap)
+ struct vop_aclcheck_args /* {
+ struct vnode *vp;
+ acl_type_t type;
+ struct acl *aclp;
+ struct ucred *cred;
+ struct thread *td;
+ } */ *ap;
+{
+
+ return (ufs_aclcheck_posix1e(ap));
+}
+
#endif /* !UFS_ACL */
diff --git a/sys/ufs/ufs/ufs_dirhash.c b/sys/ufs/ufs/ufs_dirhash.c
index 3b6d5e1fafa5..e18b8387e4cd 100644
--- a/sys/ufs/ufs/ufs_dirhash.c
+++ b/sys/ufs/ufs/ufs_dirhash.c
@@ -49,6 +49,8 @@ __FBSDID("$FreeBSD$");
#include <sys/refcount.h>
#include <sys/sysctl.h>
#include <sys/sx.h>
+#include <sys/eventhandler.h>
+#include <sys/time.h>
#include <vm/uma.h>
#include <ufs/ufs/quota.h>
@@ -81,6 +83,13 @@ SYSCTL_INT(_vfs_ufs, OID_AUTO, dirhash_mem, CTLFLAG_RD, &ufs_dirhashmem,
static int ufs_dirhashcheck = 0;
SYSCTL_INT(_vfs_ufs, OID_AUTO, dirhash_docheck, CTLFLAG_RW, &ufs_dirhashcheck,
0, "enable extra sanity tests");
+static int ufs_dirhashlowmemcount = 0;
+SYSCTL_INT(_vfs_ufs, OID_AUTO, dirhash_lowmemcount, CTLFLAG_RD,
+ &ufs_dirhashlowmemcount, 0, "number of times low memory hook called");
+static int ufs_dirhashreclaimage = 5;
+SYSCTL_INT(_vfs_ufs, OID_AUTO, dirhash_reclaimage, CTLFLAG_RW,
+ &ufs_dirhashreclaimage, 0,
+ "max time in seconds of hash inactivity before deletion in low VM events");
static int ufsdirhash_hash(struct dirhash *dh, char *name, int namelen);
@@ -90,6 +99,7 @@ static int ufsdirhash_findslot(struct dirhash *dh, char *name, int namelen,
doff_t offset);
static doff_t ufsdirhash_getprev(struct direct *dp, doff_t offset);
static int ufsdirhash_recycle(int wanted);
+static void ufsdirhash_lowmem(void);
static void ufsdirhash_free_locked(struct inode *ip);
static uma_zone_t ufsdirhash_zone;
@@ -338,9 +348,12 @@ ufsdirhash_build(struct inode *ip)
int dirblocks, i, j, memreqd, nblocks, narrays, nslots, slot;
/* Take care of a decreased sysctl value. */
- while (ufs_dirhashmem > ufs_dirhashmaxmem)
+ while (ufs_dirhashmem > ufs_dirhashmaxmem) {
if (ufsdirhash_recycle(0) != 0)
return (-1);
+ /* Recycled enough memory, so unlock the list. */
+ DIRHASHLIST_UNLOCK();
+ }
/* Check if we can/should use dirhash. */
if (ip->i_size < ufs_mindirhashsize || OFSFMT(ip->i_vnode) ||
@@ -393,6 +406,7 @@ ufsdirhash_build(struct inode *ip)
dh->dh_seqopt = 0;
dh->dh_seqoff = 0;
dh->dh_score = DH_SCOREINIT;
+ dh->dh_lastused = time_second;
/*
* Use non-blocking mallocs so that we will revert to a linear
@@ -569,6 +583,9 @@ ufsdirhash_lookup(struct inode *ip, char *name, int namelen, doff_t *offp,
/* Update the score. */
if (dh->dh_score < DH_SCOREMAX)
dh->dh_score++;
+
+ /* Update last used time. */
+ dh->dh_lastused = time_second;
DIRHASHLIST_UNLOCK();
vp = ip->i_vnode;
@@ -811,6 +828,9 @@ ufsdirhash_add(struct inode *ip, struct direct *dirp, doff_t offset)
dh->dh_hused++;
DH_ENTRY(dh, slot) = offset;
+ /* Update last used time. */
+ dh->dh_lastused = time_second;
+
/* Update the per-block summary info. */
ufsdirhash_adjfree(dh, offset, -DIRSIZ(0, dirp));
ufsdirhash_release(dh);
@@ -1150,6 +1170,44 @@ ufsdirhash_getprev(struct direct *dirp, doff_t offset)
}
/*
+ * Delete the given dirhash and reclaim its memory. Assumes that
+ * ufsdirhash_list is locked, and leaves it locked. Also assumes
+ * that dh is locked. Returns the amount of memory freed.
+ */
+static int
+ufsdirhash_destroy(struct dirhash *dh)
+{
+ doff_t **hash;
+ u_int8_t *blkfree;
+ int i, mem, narrays;
+
+ KASSERT(dh->dh_hash != NULL, ("dirhash: NULL hash on list"));
+
+ /* Remove it from the list and detach its memory. */
+ TAILQ_REMOVE(&ufsdirhash_list, dh, dh_list);
+ dh->dh_onlist = 0;
+ hash = dh->dh_hash;
+ dh->dh_hash = NULL;
+ blkfree = dh->dh_blkfree;
+ dh->dh_blkfree = NULL;
+ narrays = dh->dh_narrays;
+ mem = dh->dh_memreq;
+ dh->dh_memreq = 0;
+
+ /* Unlock dirhash and free the detached memory. */
+ ufsdirhash_release(dh);
+ for (i = 0; i < narrays; i++)
+ DIRHASH_BLKFREE(hash[i]);
+ free(hash, M_DIRHASH);
+ free(blkfree, M_DIRHASH);
+
+ /* Account for the returned memory. */
+ ufs_dirhashmem -= mem;
+
+ return (mem);
+}
+
+/*
* Try to free up `wanted' bytes by stealing memory from existing
* dirhashes. Returns zero with list locked if successful.
*/
@@ -1157,9 +1215,6 @@ static int
ufsdirhash_recycle(int wanted)
{
struct dirhash *dh;
- doff_t **hash;
- u_int8_t *blkfree;
- int i, mem, narrays;
DIRHASHLIST_LOCK();
dh = TAILQ_FIRST(&ufsdirhash_list);
@@ -1177,36 +1232,61 @@ ufsdirhash_recycle(int wanted)
dh = TAILQ_NEXT(dh, dh_list);
continue;
}
- KASSERT(dh->dh_hash != NULL, ("dirhash: NULL hash on list"));
- /* Remove it from the list and detach its memory. */
- TAILQ_REMOVE(&ufsdirhash_list, dh, dh_list);
- dh->dh_onlist = 0;
- hash = dh->dh_hash;
- dh->dh_hash = NULL;
- blkfree = dh->dh_blkfree;
- dh->dh_blkfree = NULL;
- narrays = dh->dh_narrays;
- mem = dh->dh_memreq;
- dh->dh_memreq = 0;
-
- /* Unlock everything, free the detached memory. */
- ufsdirhash_release(dh);
- DIRHASHLIST_UNLOCK();
- for (i = 0; i < narrays; i++)
- DIRHASH_BLKFREE(hash[i]);
- free(hash, M_DIRHASH);
- free(blkfree, M_DIRHASH);
-
- /* Account for the returned memory, and repeat if necessary. */
- DIRHASHLIST_LOCK();
- ufs_dirhashmem -= mem;
+ ufsdirhash_destroy(dh);
+
+ /* Repeat if necessary. */
dh = TAILQ_FIRST(&ufsdirhash_list);
}
/* Success; return with list locked. */
return (0);
}
+/*
+ * Callback that frees some dirhashes when the system is low on virtual memory.
+ */
+static void
+ufsdirhash_lowmem()
+{
+ struct dirhash *dh, *dh_temp;
+ int memfreed = 0;
+ /* XXX: this 10% may need to be adjusted */
+ int memwanted = ufs_dirhashmem / 10;
+
+ ufs_dirhashlowmemcount++;
+
+ DIRHASHLIST_LOCK();
+ /*
+ * Delete dirhashes not used for more than ufs_dirhashreclaimage
+ * seconds. If we can't get a lock on the dirhash, it will be skipped.
+ */
+ TAILQ_FOREACH_SAFE(dh, &ufsdirhash_list, dh_list, dh_temp) {
+ if (!sx_try_xlock(&dh->dh_lock))
+ continue;
+ if (time_second - dh->dh_lastused > ufs_dirhashreclaimage)
+ memfreed += ufsdirhash_destroy(dh);
+ /* Unlock if we didn't delete the dirhash */
+ else
+ ufsdirhash_release(dh);
+ }
+
+ /*
+ * If not enough memory was freed, keep deleting hashes from the head
+ * of the dirhash list. The ones closest to the head should be the
+ * oldest.
+ */
+ if (memfreed < memwanted) {
+ TAILQ_FOREACH_SAFE(dh, &ufsdirhash_list, dh_list, dh_temp) {
+ if (!sx_try_xlock(&dh->dh_lock))
+ continue;
+ memfreed += ufsdirhash_destroy(dh);
+ if (memfreed >= memwanted)
+ break;
+ }
+ }
+ DIRHASHLIST_UNLOCK();
+}
+
void
ufsdirhash_init()
@@ -1215,6 +1295,10 @@ ufsdirhash_init()
NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
mtx_init(&ufsdirhash_mtx, "dirhash list", NULL, MTX_DEF);
TAILQ_INIT(&ufsdirhash_list);
+
+ /* Register a callback function to handle low memory signals */
+ EVENTHANDLER_REGISTER(vm_lowmem, ufsdirhash_lowmem, NULL,
+ EVENTHANDLER_PRI_FIRST);
}
void
diff --git a/sys/ufs/ufs/ufs_extattr.c b/sys/ufs/ufs/ufs_extattr.c
index d034bee1f500..032d9cc34211 100644
--- a/sys/ufs/ufs/ufs_extattr.c
+++ b/sys/ufs/ufs/ufs_extattr.c
@@ -93,8 +93,10 @@ static int ufs_extattr_set(struct vnode *vp, int attrnamespace,
struct thread *td);
static int ufs_extattr_rm(struct vnode *vp, int attrnamespace,
const char *name, struct ucred *cred, struct thread *td);
+#ifdef UFS_EXTATTR_AUTOSTART
static int ufs_extattr_autostart_locked(struct mount *mp,
struct thread *td);
+#endif
static int ufs_extattr_start_locked(struct ufsmount *ump,
struct thread *td);
@@ -478,7 +480,7 @@ ufs_extattr_autostart_locked(struct mount *mp, struct thread *td)
* Does UFS_EXTATTR_FSROOTSUBDIR exist off the filesystem root?
* If so, automatically start EA's.
*/
- error = VFS_ROOT(mp, LK_EXCLUSIVE, &rvp, td);
+ error = VFS_ROOT(mp, LK_EXCLUSIVE, &rvp);
if (error) {
printf("ufs_extattr_autostart.VFS_ROOT() returned %d\n",
error);
@@ -714,9 +716,10 @@ ufs_extattr_disable(struct ufsmount *ump, int attrnamespace,
*/
int
ufs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp,
- int attrnamespace, const char *attrname, struct thread *td)
+ int attrnamespace, const char *attrname)
{
struct ufsmount *ump = VFSTOUFS(mp);
+ struct thread *td = curthread;
int error;
/*
diff --git a/sys/ufs/ufs/ufs_extern.h b/sys/ufs/ufs/ufs_extern.h
index 40a659dfdac6..b2e4a9757305 100644
--- a/sys/ufs/ufs/ufs_extern.h
+++ b/sys/ufs/ufs/ufs_extern.h
@@ -38,7 +38,6 @@ struct direct;
struct indir;
struct inode;
struct mount;
-struct netcred;
struct thread;
struct sockaddr;
struct ucred;
@@ -58,7 +57,7 @@ int ufs_bmap(struct vop_bmap_args *);
int ufs_bmaparray(struct vnode *, ufs2_daddr_t, ufs2_daddr_t *,
struct buf *, int *, int *);
int ufs_fhtovp(struct mount *, struct ufid *, struct vnode **);
-int ufs_checkpath(struct inode *, struct inode *, struct ucred *);
+int ufs_checkpath(ino_t, struct inode *, struct ucred *);
void ufs_dirbad(struct inode *, doff_t, char *);
int ufs_dirbadentry(struct vnode *, struct direct *, int);
int ufs_dirempty(struct inode *, ino_t, struct ucred *);
diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c
index bc11a6a26bef..ea73b1ff8616 100644
--- a/sys/ufs/ufs/ufs_lookup.c
+++ b/sys/ufs/ufs/ufs_lookup.c
@@ -77,6 +77,9 @@ SYSCTL_INT(_debug, OID_AUTO, dircheck, CTLFLAG_RW, &dirchk, 0, "");
/* true if old FS format...*/
#define OFSFMT(vp) ((vp)->v_mount->mnt_maxsymlinklen <= 0)
+static int ufs_lookup_(struct vnode *, struct vnode **, struct componentname *,
+ ino_t *);
+
/*
* Convert a component of a pathname into a pointer to a locked inode.
* This is a very central and rather complicated routine.
@@ -130,7 +133,14 @@ ufs_lookup(ap)
struct componentname *a_cnp;
} */ *ap;
{
- struct vnode *vdp; /* vnode for directory being searched */
+
+ return (ufs_lookup_(ap->a_dvp, ap->a_vpp, ap->a_cnp, NULL));
+}
+
+static int
+ufs_lookup_(struct vnode *vdp, struct vnode **vpp, struct componentname *cnp,
+ ino_t *dd_ino)
+{
struct inode *dp; /* inode for directory being searched */
struct buf *bp; /* a buffer of directory entries */
struct direct *ep; /* the current directory entry */
@@ -150,23 +160,15 @@ ufs_lookup(ap)
doff_t enduseful; /* pointer past last used dir slot */
u_long bmask; /* block offset mask */
int namlen, error;
- struct vnode **vpp = ap->a_vpp;
- struct componentname *cnp = ap->a_cnp;
struct ucred *cred = cnp->cn_cred;
int flags = cnp->cn_flags;
int nameiop = cnp->cn_nameiop;
- ino_t ino;
+ ino_t ino, ino1;
int ltype;
- bp = NULL;
- slotoffset = -1;
-/*
- * XXX there was a soft-update diff about this I couldn't merge.
- * I think this was the equiv.
- */
- *vpp = NULL;
+ if (vpp != NULL)
+ *vpp = NULL;
- vdp = ap->a_dvp;
dp = VTOI(vdp);
/*
@@ -177,6 +179,12 @@ ufs_lookup(ap)
*/
vnode_create_vobject(vdp, DIP(dp, i_size), cnp->cn_thread);
+ bmask = VFSTOUFS(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
+
+restart:
+ bp = NULL;
+ slotoffset = -1;
+
/*
* We now have a segment name to search for, and a directory to search.
*
@@ -194,7 +202,6 @@ ufs_lookup(ap)
slotstatus = NONE;
slotneeded = DIRECTSIZ(cnp->cn_namelen);
}
- bmask = VFSTOUFS(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
#ifdef UFS_DIRHASH
/*
@@ -363,7 +370,7 @@ foundentry:
slotoffset = i_offset;
slotsize = ep->d_reclen;
enduseful = dp->i_size;
- ap->a_cnp->cn_flags |= ISWHITEOUT;
+ cnp->cn_flags |= ISWHITEOUT;
numdirpasses--;
goto notfound;
}
@@ -397,8 +404,8 @@ notfound:
*/
if ((nameiop == CREATE || nameiop == RENAME ||
(nameiop == DELETE &&
- (ap->a_cnp->cn_flags & DOWHITEOUT) &&
- (ap->a_cnp->cn_flags & ISWHITEOUT))) &&
+ (cnp->cn_flags & DOWHITEOUT) &&
+ (cnp->cn_flags & ISWHITEOUT))) &&
(flags & ISLASTCN) && dp->i_effnlink != 0) {
/*
* Access for write is interpreted as allowing
@@ -453,7 +460,7 @@ notfound:
* Insert name into cache (as non-existent) if appropriate.
*/
if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
- cache_enter(vdp, *vpp, cnp);
+ cache_enter(vdp, NULL, cnp);
return (ENOENT);
found:
@@ -479,6 +486,11 @@ found:
if ((flags & ISLASTCN) && nameiop == LOOKUP)
dp->i_diroff = i_offset &~ (DIRBLKSIZ - 1);
+ if (dd_ino != NULL) {
+ *dd_ino = ino;
+ return (0);
+ }
+
/*
* If deleting, and at end of pathname, return
* parameters which can be used to remove file.
@@ -580,6 +592,22 @@ found:
error = vn_vget_ino(pdp, ino, cnp->cn_lkflags, &tdp);
if (error)
return (error);
+
+ /*
+ * Recheck that ".." entry in the vdp directory points
+ * to the inode we looked up before vdp lock was
+ * dropped.
+ */
+ error = ufs_lookup_(pdp, NULL, cnp, &ino1);
+ if (error) {
+ vput(tdp);
+ return (error);
+ }
+ if (ino1 != ino) {
+ vput(tdp);
+ goto restart;
+ }
+
*vpp = tdp;
} else if (dp->i_number == ino) {
VREF(vdp); /* we want ourself, ie "." */
@@ -1209,69 +1237,81 @@ ufs_dirempty(ip, parentino, cred)
return (1);
}
+static int
+ufs_dir_dd_ino(struct vnode *vp, struct ucred *cred, ino_t *dd_ino)
+{
+ struct dirtemplate dirbuf;
+ int error, namlen;
+
+ if (vp->v_type != VDIR)
+ return (ENOTDIR);
+ error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf,
+ sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE,
+ IO_NODELOCKED | IO_NOMACCHECK, cred, NOCRED, NULL, NULL);
+ if (error != 0)
+ return (error);
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+ if (OFSFMT(vp))
+ namlen = dirbuf.dotdot_type;
+ else
+ namlen = dirbuf.dotdot_namlen;
+#else
+ namlen = dirbuf.dotdot_namlen;
+#endif
+ if (namlen != 2 || dirbuf.dotdot_name[0] != '.' ||
+ dirbuf.dotdot_name[1] != '.')
+ return (ENOTDIR);
+ *dd_ino = dirbuf.dotdot_ino;
+ return (0);
+}
+
/*
* Check if source directory is in the path of the target directory.
* Target is supplied locked, source is unlocked.
* The target is always vput before returning.
*/
int
-ufs_checkpath(source, target, cred)
- struct inode *source, *target;
- struct ucred *cred;
+ufs_checkpath(ino_t source_ino, struct inode *target, struct ucred *cred)
{
- struct vnode *vp;
- int error, namlen;
- ino_t rootino;
- struct dirtemplate dirbuf;
+ struct vnode *vp, *vp1;
+ int error;
+ ino_t dd_ino;
vp = ITOV(target);
- if (target->i_number == source->i_number) {
+ if (target->i_number == source_ino) {
error = EEXIST;
goto out;
}
- rootino = ROOTINO;
error = 0;
- if (target->i_number == rootino)
+ if (target->i_number == ROOTINO)
goto out;
for (;;) {
- if (vp->v_type != VDIR) {
- error = ENOTDIR;
- break;
- }
- error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf,
- sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE,
- IO_NODELOCKED | IO_NOMACCHECK, cred, NOCRED, (int *)0,
- (struct thread *)0);
+ error = ufs_dir_dd_ino(vp, cred, &dd_ino);
if (error != 0)
break;
-# if (BYTE_ORDER == LITTLE_ENDIAN)
- if (OFSFMT(vp))
- namlen = dirbuf.dotdot_type;
- else
- namlen = dirbuf.dotdot_namlen;
-# else
- namlen = dirbuf.dotdot_namlen;
-# endif
- if (namlen != 2 ||
- dirbuf.dotdot_name[0] != '.' ||
- dirbuf.dotdot_name[1] != '.') {
- error = ENOTDIR;
- break;
- }
- if (dirbuf.dotdot_ino == source->i_number) {
+ if (dd_ino == source_ino) {
error = EINVAL;
break;
}
- if (dirbuf.dotdot_ino == rootino)
+ if (dd_ino == ROOTINO)
break;
- vput(vp);
- error = VFS_VGET(vp->v_mount, dirbuf.dotdot_ino,
- LK_EXCLUSIVE, &vp);
- if (error) {
- vp = NULL;
+ error = vn_vget_ino(vp, dd_ino, LK_EXCLUSIVE, &vp1);
+ if (error != 0)
+ break;
+ /* Recheck that ".." still points to vp1 after relock of vp */
+ error = ufs_dir_dd_ino(vp, cred, &dd_ino);
+ if (error != 0) {
+ vput(vp1);
break;
}
+ /* Redo the check of ".." if directory was reparented */
+ if (dd_ino != VTOI(vp1)->i_number) {
+ vput(vp1);
+ continue;
+ }
+ vput(vp);
+ vp = vp1;
}
out:
diff --git a/sys/ufs/ufs/ufs_vfsops.c b/sys/ufs/ufs/ufs_vfsops.c
index 33b35aff6ab4..3abd5eb78399 100644
--- a/sys/ufs/ufs/ufs_vfsops.c
+++ b/sys/ufs/ufs/ufs_vfsops.c
@@ -66,11 +66,10 @@ MALLOC_DEFINE(M_UFSMNT, "ufs_mount", "UFS mount structure");
* Return the root of a filesystem.
*/
int
-ufs_root(mp, flags, vpp, td)
+ufs_root(mp, flags, vpp)
struct mount *mp;
int flags;
struct vnode **vpp;
- struct thread *td;
{
struct vnode *nvp;
int error;
@@ -86,18 +85,19 @@ ufs_root(mp, flags, vpp, td)
* Do operations associated with quotas
*/
int
-ufs_quotactl(mp, cmds, id, arg, td)
+ufs_quotactl(mp, cmds, id, arg)
struct mount *mp;
int cmds;
uid_t id;
void *arg;
- struct thread *td;
{
#ifndef QUOTA
return (EOPNOTSUPP);
#else
+ struct thread *td;
int cmd, type, error;
+ td = curthread;
cmd = cmds >> SUBCMDSHIFT;
type = cmds & SUBCMDMASK;
if (id == -1) {
diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c
index 675c55cf2006..08b77ae07290 100644
--- a/sys/ufs/ufs/ufs_vnops.c
+++ b/sys/ufs/ufs/ufs_vnops.c
@@ -37,7 +37,6 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include "opt_mac.h"
#include "opt_quota.h"
#include "opt_suiddir.h"
#include "opt_ufs.h"
@@ -61,7 +60,6 @@ __FBSDID("$FreeBSD$");
#include <sys/lockf.h>
#include <sys/conf.h>
#include <sys/acl.h>
-#include <sys/jail.h>
#include <machine/mutex.h>
@@ -114,6 +112,7 @@ static vop_symlink_t ufs_symlink;
static vop_whiteout_t ufs_whiteout;
static vop_close_t ufsfifo_close;
static vop_kqfilter_t ufsfifo_kqfilter;
+static vop_pathconf_t ufsfifo_pathconf;
/*
* A virgin directory (no blushing please).
@@ -157,11 +156,11 @@ ufs_itimes_locked(struct vnode *vp)
if (ip->i_flag & IN_UPDATE) {
DIP_SET(ip, i_mtime, ts.tv_sec);
DIP_SET(ip, i_mtimensec, ts.tv_nsec);
- ip->i_modrev++;
}
if (ip->i_flag & IN_CHANGE) {
DIP_SET(ip, i_ctime, ts.tv_sec);
DIP_SET(ip, i_ctimensec, ts.tv_nsec);
+ DIP_SET(ip, i_modrev, DIP(ip, i_modrev) + 1);
}
out:
@@ -374,7 +373,7 @@ relock:
#ifdef UFS_ACL
if ((vp->v_mount->mnt_flag & MNT_ACLS) != 0) {
- acl = uma_zalloc(acl_zone, M_WAITOK);
+ acl = acl_alloc(M_WAITOK);
error = VOP_GETACL(vp, ACL_TYPE_ACCESS, acl, ap->a_cred,
ap->a_td);
switch (error) {
@@ -398,7 +397,7 @@ relock:
error = vaccess(vp->v_type, ip->i_mode, ip->i_uid,
ip->i_gid, ap->a_accmode, ap->a_cred, NULL);
}
- uma_zfree(acl_zone, acl);
+ acl_free(acl);
} else
#endif /* !UFS_ACL */
error = vaccess(vp->v_type, ip->i_mode, ip->i_uid, ip->i_gid,
@@ -446,6 +445,7 @@ ufs_getattr(ap)
vap->va_ctime.tv_sec = ip->i_din1->di_ctime;
vap->va_ctime.tv_nsec = ip->i_din1->di_ctimensec;
vap->va_bytes = dbtob((u_quad_t)ip->i_din1->di_blocks);
+ vap->va_filerev = ip->i_din1->di_modrev;
} else {
vap->va_rdev = ip->i_din2->di_rdev;
vap->va_size = ip->i_din2->di_size;
@@ -456,12 +456,12 @@ ufs_getattr(ap)
vap->va_birthtime.tv_sec = ip->i_din2->di_birthtime;
vap->va_birthtime.tv_nsec = ip->i_din2->di_birthnsec;
vap->va_bytes = dbtob((u_quad_t)ip->i_din2->di_blocks);
+ vap->va_filerev = ip->i_din2->di_modrev;
}
vap->va_flags = ip->i_flags;
vap->va_gen = ip->i_gen;
vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
vap->va_type = IFTOVT(ip->i_mode);
- vap->va_filerev = ip->i_modrev;
return (0);
}
@@ -1036,6 +1036,7 @@ ufs_rename(ap)
struct direct newdir;
int doingdirectory = 0, oldparent = 0, newparent = 0;
int error = 0, ioflag;
+ ino_t fvp_ino;
#ifdef INVARIANTS
if ((tcnp->cn_flags & HASBUF) == 0 ||
@@ -1146,6 +1147,7 @@ abortit:
* call to checkpath().
*/
error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_thread);
+ fvp_ino = ip->i_number;
VOP_UNLOCK(fvp, 0);
if (oldparent != dp->i_number)
newparent = dp->i_number;
@@ -1154,7 +1156,7 @@ abortit:
goto bad;
if (xp != NULL)
vput(tvp);
- error = ufs_checkpath(ip, dp, tcnp->cn_cred);
+ error = ufs_checkpath(fvp_ino, dp, tcnp->cn_cred);
if (error)
goto out;
if ((tcnp->cn_flags & SAVESTART) == 0)
@@ -1447,6 +1449,7 @@ ufs_mkdir(ap)
{
#ifdef QUOTA
struct ucred ucred, *ucp;
+ gid_t ucred_group;
ucp = cnp->cn_cred;
#endif
/*
@@ -1474,6 +1477,7 @@ ufs_mkdir(ap)
refcount_init(&ucred.cr_ref, 1);
ucred.cr_uid = ip->i_uid;
ucred.cr_ngroups = 1;
+ ucred.cr_groups = &ucred_group;
ucred.cr_groups[0] = dp->i_gid;
ucp = &ucred;
}
@@ -1507,8 +1511,8 @@ ufs_mkdir(ap)
#ifdef UFS_ACL
acl = dacl = NULL;
if ((dvp->v_mount->mnt_flag & MNT_ACLS) != 0) {
- acl = uma_zalloc(acl_zone, M_WAITOK);
- dacl = uma_zalloc(acl_zone, M_WAITOK);
+ acl = acl_alloc(M_WAITOK);
+ dacl = acl_alloc(M_WAITOK);
/*
* Retrieve default ACL from parent, if any.
@@ -1538,16 +1542,16 @@ ufs_mkdir(ap)
*/
ip->i_mode = dmode;
DIP_SET(ip, i_mode, dmode);
- uma_zfree(acl_zone, acl);
- uma_zfree(acl_zone, dacl);
+ acl_free(acl);
+ acl_free(dacl);
dacl = acl = NULL;
break;
default:
UFS_VFREE(tvp, ip->i_number, dmode);
vput(tvp);
- uma_zfree(acl_zone, acl);
- uma_zfree(acl_zone, dacl);
+ acl_free(acl);
+ acl_free(dacl);
return (error);
}
} else {
@@ -1617,13 +1621,13 @@ ufs_mkdir(ap)
break;
default:
- uma_zfree(acl_zone, acl);
- uma_zfree(acl_zone, dacl);
+ acl_free(acl);
+ acl_free(dacl);
dacl = acl = NULL;
goto bad;
}
- uma_zfree(acl_zone, acl);
- uma_zfree(acl_zone, dacl);
+ acl_free(acl);
+ acl_free(dacl);
dacl = acl = NULL;
}
#endif /* !UFS_ACL */
@@ -1689,9 +1693,9 @@ bad:
} else {
#ifdef UFS_ACL
if (acl != NULL)
- uma_zfree(acl_zone, acl);
+ acl_free(acl);
if (dacl != NULL)
- uma_zfree(acl_zone, dacl);
+ acl_free(dacl);
#endif
dp->i_effnlink--;
dp->i_nlink--;
@@ -1848,7 +1852,7 @@ ufs_symlink(ap)
} else
error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
UIO_SYSSPACE, IO_NODELOCKED | IO_NOMACCHECK,
- ap->a_cnp->cn_cred, NOCRED, (int *)0, (struct thread *)0);
+ ap->a_cnp->cn_cred, NOCRED, NULL, NULL);
if (error)
vput(vp);
return (error);
@@ -2100,6 +2104,29 @@ ufsfifo_kqfilter(ap)
}
/*
+ * Return POSIX pathconf information applicable to fifos.
+ */
+static int
+ufsfifo_pathconf(ap)
+ struct vop_pathconf_args /* {
+ struct vnode *a_vp;
+ int a_name;
+ int *a_retval;
+ } */ *ap;
+{
+
+ switch (ap->a_name) {
+ case _PC_ACL_EXTENDED:
+ case _PC_ACL_PATH_MAX:
+ case _PC_MAC_PRESENT:
+ return (ufs_pathconf(ap));
+ default:
+ return (fifo_specops.vop_pathconf(ap));
+ }
+ /* NOTREACHED */
+}
+
+/*
* Return POSIX pathconf information applicable to ufs filesystems.
*/
static int
@@ -2223,7 +2250,6 @@ ufs_vinit(mntp, fifoops, vpp)
ASSERT_VOP_LOCKED(vp, "ufs_vinit");
if (ip->i_number == ROOTINO)
vp->v_vflag |= VV_ROOT;
- ip->i_modrev = init_va_filerev();
*vpp = vp;
return (0);
}
@@ -2266,6 +2292,7 @@ ufs_makeinode(mode, dvp, vpp, cnp)
{
#ifdef QUOTA
struct ucred ucred, *ucp;
+ gid_t ucred_group;
ucp = cnp->cn_cred;
#endif
/*
@@ -2292,6 +2319,7 @@ ufs_makeinode(mode, dvp, vpp, cnp)
refcount_init(&ucred.cr_ref, 1);
ucred.cr_uid = ip->i_uid;
ucred.cr_ngroups = 1;
+ ucred.cr_groups = &ucred_group;
ucred.cr_groups[0] = pdir->i_gid;
ucp = &ucred;
#endif
@@ -2325,7 +2353,7 @@ ufs_makeinode(mode, dvp, vpp, cnp)
#ifdef UFS_ACL
acl = NULL;
if ((dvp->v_mount->mnt_flag & MNT_ACLS) != 0) {
- acl = uma_zalloc(acl_zone, M_WAITOK);
+ acl = acl_alloc(M_WAITOK);
/*
* Retrieve default ACL for parent, if any.
@@ -2360,14 +2388,14 @@ ufs_makeinode(mode, dvp, vpp, cnp)
*/
ip->i_mode = mode;
DIP_SET(ip, i_mode, mode);
- uma_zfree(acl_zone, acl);
+ acl_free(acl);
acl = NULL;
break;
default:
UFS_VFREE(tvp, ip->i_number, mode);
vput(tvp);
- uma_zfree(acl_zone, acl);
+ acl_free(acl);
acl = NULL;
return (error);
}
@@ -2433,10 +2461,10 @@ ufs_makeinode(mode, dvp, vpp, cnp)
break;
default:
- uma_zfree(acl_zone, acl);
+ acl_free(acl);
goto bad;
}
- uma_zfree(acl_zone, acl);
+ acl_free(acl);
}
#endif /* !UFS_ACL */
ufs_makedirentry(ip, cnp, &newdir);
@@ -2518,6 +2546,7 @@ struct vop_vector ufs_fifoops = {
.vop_inactive = ufs_inactive,
.vop_kqfilter = ufsfifo_kqfilter,
.vop_markatime = ufs_markatime,
+ .vop_pathconf = ufsfifo_pathconf,
.vop_print = ufs_print,
.vop_read = VOP_PANIC,
.vop_reclaim = ufs_reclaim,