aboutsummaryrefslogtreecommitdiff
path: root/sys/ufs
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2009-09-17 13:31:39 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2009-09-17 13:31:39 +0000
commit7d4b968b0fa6afc6bca132c27e2041c979ee6101 (patch)
tree0c2c6d031c26dd91d9604be7af3834277e335263 /sys/ufs
parent8bd6a3ab4b32283502a1b58731eb0d0750b4f124 (diff)
parentab8b490a63599c4b0a045c989c1a7162b161d2a5 (diff)
downloadsrc-7d4b968b0fa6afc6bca132c27e2041c979ee6101.tar.gz
src-7d4b968b0fa6afc6bca132c27e2041c979ee6101.zip
Merge from head up to r188941 (last revision before the USB stack switch)
Notes
Notes: svn path=/projects/quota64/; revision=197278
Diffstat (limited to 'sys/ufs')
-rw-r--r--sys/ufs/ffs/ffs_alloc.c31
-rw-r--r--sys/ufs/ffs/ffs_balloc.c42
-rw-r--r--sys/ufs/ffs/ffs_extern.h6
-rw-r--r--sys/ufs/ffs/ffs_inode.c24
-rw-r--r--sys/ufs/ffs/ffs_vfsops.c27
-rw-r--r--sys/ufs/ffs/ffs_vnops.c14
-rw-r--r--sys/ufs/ufs/ufs_dirhash.c12
-rw-r--r--sys/ufs/ufs/ufs_extattr.c45
-rw-r--r--sys/ufs/ufs/ufs_lookup.c23
-rw-r--r--sys/ufs/ufs/ufs_quota.c16
-rw-r--r--sys/ufs/ufs/ufs_vfsops.c4
-rw-r--r--sys/ufs/ufs/ufs_vnops.c35
12 files changed, 174 insertions, 105 deletions
diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c
index a72137ef4660..4748f682101c 100644
--- a/sys/ufs/ffs/ffs_alloc.c
+++ b/sys/ufs/ffs/ffs_alloc.c
@@ -130,10 +130,10 @@ static int ffs_reallocblks_ufs2(struct vop_reallocblks_args *);
* available block is located.
*/
int
-ffs_alloc(ip, lbn, bpref, size, cred, bnp)
+ffs_alloc(ip, lbn, bpref, size, flags, cred, bnp)
struct inode *ip;
ufs2_daddr_t lbn, bpref;
- int size;
+ int size, flags;
struct ucred *cred;
ufs2_daddr_t *bnp;
{
@@ -191,7 +191,10 @@ retry:
UFS_UNLOCK(ump);
}
DIP_SET(ip, i_blocks, DIP(ip, i_blocks) + delta);
- ip->i_flag |= IN_CHANGE | IN_UPDATE;
+ if (flags & IO_EXT)
+ ip->i_flag |= IN_CHANGE;
+ else
+ ip->i_flag |= IN_CHANGE | IN_UPDATE;
*bnp = bno;
return (0);
}
@@ -227,12 +230,12 @@ nospace:
* invoked to get an appropriate block.
*/
int
-ffs_realloccg(ip, lbprev, bprev, bpref, osize, nsize, cred, bpp)
+ffs_realloccg(ip, lbprev, bprev, bpref, osize, nsize, flags, cred, bpp)
struct inode *ip;
ufs2_daddr_t lbprev;
ufs2_daddr_t bprev;
ufs2_daddr_t bpref;
- int osize, nsize;
+ int osize, nsize, flags;
struct ucred *cred;
struct buf **bpp;
{
@@ -317,7 +320,10 @@ retry:
UFS_UNLOCK(ump);
}
DIP_SET(ip, i_blocks, DIP(ip, i_blocks) + delta);
- ip->i_flag |= IN_CHANGE | IN_UPDATE;
+ if (flags & IO_EXT)
+ ip->i_flag |= IN_CHANGE;
+ else
+ 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)
@@ -392,7 +398,10 @@ retry:
UFS_UNLOCK(ump);
}
DIP_SET(ip, i_blocks, DIP(ip, i_blocks) + delta);
- ip->i_flag |= IN_CHANGE | IN_UPDATE;
+ if (flags & IO_EXT)
+ ip->i_flag |= IN_CHANGE;
+ else
+ 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)
@@ -1849,7 +1858,7 @@ ffs_blkfree(ump, fs, devvp, bno, size, inum)
struct cdev *dev;
cg = dtog(fs, bno);
- if (devvp->v_type != VCHR) {
+ if (devvp->v_type == VREG) {
/* devvp is a snapshot */
dev = VTOI(devvp)->i_devvp->v_rdev;
cgblkno = fragstoblks(fs, cgtod(fs, cg));
@@ -1894,7 +1903,7 @@ ffs_blkfree(ump, fs, devvp, bno, size, inum)
if (size == fs->fs_bsize) {
fragno = fragstoblks(fs, cgbno);
if (!ffs_isfreeblock(fs, blksfree, fragno)) {
- if (devvp->v_type != VCHR) {
+ if (devvp->v_type == VREG) {
UFS_UNLOCK(ump);
/* devvp is a snapshot */
brelse(bp);
@@ -2047,7 +2056,7 @@ ffs_freefile(ump, fs, devvp, ino, mode)
struct cdev *dev;
cg = ino_to_cg(fs, ino);
- if (devvp->v_type != VCHR) {
+ if (devvp->v_type == VREG) {
/* devvp is a snapshot */
dev = VTOI(devvp)->i_devvp->v_rdev;
cgbno = fragstoblks(fs, cgtod(fs, cg));
@@ -2113,7 +2122,7 @@ ffs_checkfreefile(fs, devvp, ino)
u_int8_t *inosused;
cg = ino_to_cg(fs, ino);
- if (devvp->v_type != VCHR) {
+ if (devvp->v_type == VREG) {
/* devvp is a snapshot */
cgbno = fragstoblks(fs, cgtod(fs, cg));
} else {
diff --git a/sys/ufs/ffs/ffs_balloc.c b/sys/ufs/ffs/ffs_balloc.c
index 0bd895f57410..a12f96e60d0e 100644
--- a/sys/ufs/ffs/ffs_balloc.c
+++ b/sys/ufs/ffs/ffs_balloc.c
@@ -133,7 +133,8 @@ ffs_balloc_ufs1(struct vnode *vp, off_t startoffset, int size,
UFS_LOCK(ump);
error = ffs_realloccg(ip, nb, dp->di_db[nb],
ffs_blkpref_ufs1(ip, lastlbn, (int)nb,
- &dp->di_db[0]), osize, (int)fs->fs_bsize, cred, &bp);
+ &dp->di_db[0]), osize, (int)fs->fs_bsize, flags,
+ cred, &bp);
if (error)
return (error);
if (DOINGSOFTDEP(vp))
@@ -184,7 +185,8 @@ ffs_balloc_ufs1(struct vnode *vp, off_t startoffset, int size,
UFS_LOCK(ump);
error = ffs_realloccg(ip, lbn, dp->di_db[lbn],
ffs_blkpref_ufs1(ip, lbn, (int)lbn,
- &dp->di_db[0]), osize, nsize, cred, &bp);
+ &dp->di_db[0]), osize, nsize, flags,
+ cred, &bp);
if (error)
return (error);
if (DOINGSOFTDEP(vp))
@@ -200,7 +202,7 @@ ffs_balloc_ufs1(struct vnode *vp, off_t startoffset, int size,
UFS_LOCK(ump);
error = ffs_alloc(ip, lbn,
ffs_blkpref_ufs1(ip, lbn, (int)lbn, &dp->di_db[0]),
- nsize, cred, &newb);
+ nsize, flags, cred, &newb);
if (error)
return (error);
bp = getblk(vp, lbn, nsize, 0, 0, 0);
@@ -241,7 +243,7 @@ ffs_balloc_ufs1(struct vnode *vp, off_t startoffset, int size,
UFS_LOCK(ump);
pref = ffs_blkpref_ufs1(ip, lbn, 0, (ufs1_daddr_t *)0);
if ((error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize,
- cred, &newb)) != 0) {
+ flags, cred, &newb)) != 0) {
curthread->td_pflags &= saved_inbdflush;
return (error);
}
@@ -291,8 +293,8 @@ ffs_balloc_ufs1(struct vnode *vp, off_t startoffset, int size,
UFS_LOCK(ump);
if (pref == 0)
pref = ffs_blkpref_ufs1(ip, lbn, 0, (ufs1_daddr_t *)0);
- if ((error =
- ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, &newb)) != 0) {
+ if ((error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize,
+ flags, cred, &newb)) != 0) {
brelse(bp);
goto fail;
}
@@ -346,7 +348,7 @@ ffs_balloc_ufs1(struct vnode *vp, off_t startoffset, int size,
UFS_LOCK(ump);
pref = ffs_blkpref_ufs1(ip, lbn, indirs[i].in_off, &bap[0]);
error = ffs_alloc(ip,
- lbn, pref, (int)fs->fs_bsize, cred, &newb);
+ lbn, pref, (int)fs->fs_bsize, flags, cred, &newb);
if (error) {
brelse(bp);
goto fail;
@@ -534,7 +536,7 @@ ffs_balloc_ufs2(struct vnode *vp, off_t startoffset, int size,
dp->di_extb[nb],
ffs_blkpref_ufs2(ip, lastlbn, (int)nb,
&dp->di_extb[0]), osize,
- (int)fs->fs_bsize, cred, &bp);
+ (int)fs->fs_bsize, flags, cred, &bp);
if (error)
return (error);
if (DOINGSOFTDEP(vp))
@@ -545,7 +547,7 @@ ffs_balloc_ufs2(struct vnode *vp, off_t startoffset, int size,
dp->di_extsize = smalllblktosize(fs, nb + 1);
dp->di_extb[nb] = dbtofsb(fs, bp->b_blkno);
bp->b_xflags |= BX_ALTDATA;
- ip->i_flag |= IN_CHANGE | IN_UPDATE;
+ ip->i_flag |= IN_CHANGE;
if (flags & IO_SYNC)
bwrite(bp);
else
@@ -588,7 +590,8 @@ ffs_balloc_ufs2(struct vnode *vp, off_t startoffset, int size,
error = ffs_realloccg(ip, -1 - lbn,
dp->di_extb[lbn],
ffs_blkpref_ufs2(ip, lbn, (int)lbn,
- &dp->di_extb[0]), osize, nsize, cred, &bp);
+ &dp->di_extb[0]), osize, nsize, flags,
+ cred, &bp);
if (error)
return (error);
bp->b_xflags |= BX_ALTDATA;
@@ -605,7 +608,7 @@ ffs_balloc_ufs2(struct vnode *vp, off_t startoffset, int size,
UFS_LOCK(ump);
error = ffs_alloc(ip, lbn,
ffs_blkpref_ufs2(ip, lbn, (int)lbn, &dp->di_extb[0]),
- nsize, cred, &newb);
+ nsize, flags, cred, &newb);
if (error)
return (error);
bp = getblk(vp, -1 - lbn, nsize, 0, 0, 0);
@@ -618,7 +621,7 @@ ffs_balloc_ufs2(struct vnode *vp, off_t startoffset, int size,
nsize, 0, bp);
}
dp->di_extb[lbn] = dbtofsb(fs, bp->b_blkno);
- ip->i_flag |= IN_CHANGE | IN_UPDATE;
+ ip->i_flag |= IN_CHANGE;
*bpp = bp;
return (0);
}
@@ -636,7 +639,7 @@ ffs_balloc_ufs2(struct vnode *vp, off_t startoffset, int size,
error = ffs_realloccg(ip, nb, dp->di_db[nb],
ffs_blkpref_ufs2(ip, lastlbn, (int)nb,
&dp->di_db[0]), osize, (int)fs->fs_bsize,
- cred, &bp);
+ flags, cred, &bp);
if (error)
return (error);
if (DOINGSOFTDEP(vp))
@@ -688,7 +691,8 @@ ffs_balloc_ufs2(struct vnode *vp, off_t startoffset, int size,
UFS_LOCK(ump);
error = ffs_realloccg(ip, lbn, dp->di_db[lbn],
ffs_blkpref_ufs2(ip, lbn, (int)lbn,
- &dp->di_db[0]), osize, nsize, cred, &bp);
+ &dp->di_db[0]), osize, nsize, flags,
+ cred, &bp);
if (error)
return (error);
if (DOINGSOFTDEP(vp))
@@ -704,7 +708,7 @@ ffs_balloc_ufs2(struct vnode *vp, off_t startoffset, int size,
UFS_LOCK(ump);
error = ffs_alloc(ip, lbn,
ffs_blkpref_ufs2(ip, lbn, (int)lbn,
- &dp->di_db[0]), nsize, cred, &newb);
+ &dp->di_db[0]), nsize, flags, cred, &newb);
if (error)
return (error);
bp = getblk(vp, lbn, nsize, 0, 0, 0);
@@ -745,7 +749,7 @@ ffs_balloc_ufs2(struct vnode *vp, off_t startoffset, int size,
UFS_LOCK(ump);
pref = ffs_blkpref_ufs2(ip, lbn, 0, (ufs2_daddr_t *)0);
if ((error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize,
- cred, &newb)) != 0) {
+ flags, cred, &newb)) != 0) {
curthread->td_pflags &= saved_inbdflush;
return (error);
}
@@ -795,8 +799,8 @@ ffs_balloc_ufs2(struct vnode *vp, off_t startoffset, int size,
UFS_LOCK(ump);
if (pref == 0)
pref = ffs_blkpref_ufs2(ip, lbn, 0, (ufs2_daddr_t *)0);
- if ((error =
- ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, &newb)) != 0) {
+ if ((error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize,
+ flags, cred, &newb)) != 0) {
brelse(bp);
goto fail;
}
@@ -850,7 +854,7 @@ ffs_balloc_ufs2(struct vnode *vp, off_t startoffset, int size,
UFS_LOCK(ump);
pref = ffs_blkpref_ufs2(ip, lbn, indirs[i].in_off, &bap[0]);
error = ffs_alloc(ip,
- lbn, pref, (int)fs->fs_bsize, cred, &newb);
+ lbn, pref, (int)fs->fs_bsize, flags, cred, &newb);
if (error) {
brelse(bp);
goto fail;
diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h
index 4a2f3a23a65d..7e32ced2ebe2 100644
--- a/sys/ufs/ffs/ffs_extern.h
+++ b/sys/ufs/ffs/ffs_extern.h
@@ -48,8 +48,8 @@ struct vnode;
struct vop_fsync_args;
struct vop_reallocblks_args;
-int ffs_alloc(struct inode *,
- ufs2_daddr_t, ufs2_daddr_t, int, struct ucred *, ufs2_daddr_t *);
+int ffs_alloc(struct inode *, ufs2_daddr_t, ufs2_daddr_t, int, int,
+ struct ucred *, ufs2_daddr_t *);
int ffs_balloc_ufs1(struct vnode *a_vp, off_t a_startoffset, int a_size,
struct ucred *a_cred, int a_flags, struct buf **a_bpp);
int ffs_balloc_ufs2(struct vnode *a_vp, off_t a_startoffset, int a_size,
@@ -72,7 +72,7 @@ void ffs_load_inode(struct buf *, struct inode *, struct fs *, ino_t);
int ffs_mountroot(void);
int ffs_reallocblks(struct vop_reallocblks_args *);
int ffs_realloccg(struct inode *, ufs2_daddr_t, ufs2_daddr_t,
- ufs2_daddr_t, int, int, struct ucred *, struct buf **);
+ ufs2_daddr_t, int, int, int, struct ucred *, struct buf **);
int ffs_sbupdate(struct ufsmount *, int, int);
void ffs_setblock(struct fs *, u_char *, ufs1_daddr_t);
int ffs_snapblkfree(struct fs *, struct vnode *, ufs2_daddr_t, long, ino_t);
diff --git a/sys/ufs/ffs/ffs_inode.c b/sys/ufs/ffs/ffs_inode.c
index fa679ef1f812..b2f906730121 100644
--- a/sys/ufs/ffs/ffs_inode.c
+++ b/sys/ufs/ffs/ffs_inode.c
@@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
#include <vm/vm.h>
#include <vm/vm_extern.h>
+#include <vm/vm_object.h>
#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
@@ -128,6 +129,18 @@ ffs_update(vp, waitfor)
}
}
+static void
+ffs_pages_remove(struct vnode *vp, vm_pindex_t start, vm_pindex_t end)
+{
+ vm_object_t object;
+
+ if ((object = vp->v_object) == NULL)
+ return;
+ VM_OBJECT_LOCK(object);
+ vm_object_page_remove(object, start, end, FALSE);
+ VM_OBJECT_UNLOCK(object);
+}
+
#define SINGLE 0 /* index of single indirect block */
#define DOUBLE 1 /* index of double indirect block */
#define TRIPLE 2 /* index of triple indirect block */
@@ -205,12 +218,14 @@ ffs_truncate(vp, length, flags, cred, td)
(void) chkdq(ip, -extblocks, NOCRED, 0);
#endif
vinvalbuf(vp, V_ALT, 0, 0);
+ ffs_pages_remove(vp,
+ OFF_TO_IDX(lblktosize(fs, -extblocks)), 0);
ip->i_din2->di_extsize = 0;
for (i = 0; i < NXADDR; i++) {
oldblks[i] = ip->i_din2->di_extb[i];
ip->i_din2->di_extb[i] = 0;
}
- ip->i_flag |= IN_CHANGE | IN_UPDATE;
+ ip->i_flag |= IN_CHANGE;
if ((error = ffs_update(vp, 1)))
return (error);
for (i = 0; i < NXADDR; i++) {
@@ -281,6 +296,9 @@ ffs_truncate(vp, length, flags, cred, td)
IO_EXT | IO_NORMAL : IO_NORMAL);
ASSERT_VOP_LOCKED(vp, "ffs_truncate1");
vinvalbuf(vp, needextclean ? 0 : V_NORMAL, 0, 0);
+ if (!needextclean)
+ ffs_pages_remove(vp, 0,
+ OFF_TO_IDX(lblktosize(fs, -extblocks)));
vnode_pager_setsize(vp, 0);
ip->i_flag |= IN_CHANGE | IN_UPDATE;
return (ffs_update(vp, 0));
@@ -296,8 +314,10 @@ ffs_truncate(vp, length, flags, cred, td)
vnode_pager_setsize(vp, length);
flags |= BA_CLRBUF;
error = UFS_BALLOC(vp, length - 1, 1, cred, flags, &bp);
- if (error)
+ if (error) {
+ vnode_pager_setsize(vp, osize);
return (error);
+ }
ip->i_size = length;
DIP_SET(ip, i_size, length);
if (bp->b_bufsize == fs->fs_bsize)
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
index 563473c14938..95dbeb1f0989 100644
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -622,10 +622,13 @@ ffs_mountfs(devvp, mp, td)
struct g_consumer *cp;
struct mount *nmp;
- dev = devvp->v_rdev;
+ bp = NULL;
+ ump = NULL;
cred = td ? td->td_ucred : NOCRED;
-
ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
+
+ dev = devvp->v_rdev;
+ dev_ref(dev);
DROP_GIANT();
g_topology_lock();
error = g_vfs_open(devvp, &cp, "ffs", ronly ? 0 : 1);
@@ -640,7 +643,7 @@ ffs_mountfs(devvp, mp, td)
PICKUP_GIANT();
VOP_UNLOCK(devvp, 0);
if (error)
- return (error);
+ goto out;
if (devvp->v_rdev->si_iosize_max != 0)
mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max;
if (mp->mnt_iosize_max > MAXPHYS)
@@ -649,8 +652,6 @@ ffs_mountfs(devvp, mp, td)
devvp->v_bufobj.bo_private = cp;
devvp->v_bufobj.bo_ops = &ffs_ops;
- bp = NULL;
- ump = NULL;
fs = NULL;
sblockloc = 0;
/*
@@ -921,6 +922,7 @@ out:
free(ump, M_UFSMNT);
mp->mnt_data = NULL;
}
+ dev_rel(dev);
return (error);
}
@@ -1030,6 +1032,9 @@ ffs_unmount(mp, mntflags, td)
struct ufsmount *ump = VFSTOUFS(mp);
struct fs *fs;
int error, flags, susp;
+#ifdef UFS_EXTATTR
+ int e_restart;
+#endif
flags = 0;
fs = ump->um_fs;
@@ -1043,8 +1048,10 @@ ffs_unmount(mp, mntflags, td)
if (error != EOPNOTSUPP)
printf("ffs_unmount: ufs_extattr_stop returned %d\n",
error);
+ e_restart = 0;
} else {
ufs_extattr_uepm_destroy(&ump->um_extattr);
+ e_restart = 1;
}
#endif
if (susp) {
@@ -1102,6 +1109,7 @@ ffs_unmount(mp, mntflags, td)
g_topology_unlock();
PICKUP_GIANT();
vrele(ump->um_devvp);
+ dev_rel(ump->um_dev);
mtx_destroy(UFS_MTX(ump));
if (mp->mnt_gjprovider != NULL) {
free(mp->mnt_gjprovider, M_UFSMNT);
@@ -1121,6 +1129,15 @@ fail:
vfs_write_resume(mp);
vn_start_write(NULL, &mp, V_WAIT);
}
+#ifdef UFS_EXTATTR
+ if (e_restart) {
+ ufs_extattr_uepm_init(&ump->um_extattr);
+#ifdef UFS_EXTATTR_AUTOSTART
+ (void) ufs_extattr_autostart(mp, td);
+#endif
+ }
+#endif
+
return (error);
}
diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c
index 38dc2b67f6d7..ca2efa619033 100644
--- a/sys/ufs/ffs/ffs_vnops.c
+++ b/sys/ufs/ffs/ffs_vnops.c
@@ -723,8 +723,10 @@ ffs_write(ap)
/* XXX is uio->uio_offset the right thing here? */
error = UFS_BALLOC(vp, uio->uio_offset, xfersize,
ap->a_cred, flags, &bp);
- if (error != 0)
+ if (error != 0) {
+ vnode_pager_setsize(vp, ip->i_size);
break;
+ }
/*
* If the buffer is not valid we have to clear out any
* garbage data from the pages instantiated for the buffer.
@@ -1004,14 +1006,6 @@ ffs_extread(struct vnode *vp, struct uio *uio, int ioflag)
bqrelse(bp);
}
}
-
- if ((error == 0 || uio->uio_resid != orig_resid) &&
- (vp->v_mount->mnt_flag & MNT_NOATIME) == 0 &&
- (ip->i_flag & IN_ACCESS) == 0) {
- VI_LOCK(vp);
- ip->i_flag |= IN_ACCESS;
- VI_UNLOCK(vp);
- }
return (error);
}
@@ -1117,7 +1111,7 @@ ffs_extwrite(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *ucred)
bdwrite(bp);
if (error || xfersize == 0)
break;
- ip->i_flag |= IN_CHANGE | IN_UPDATE;
+ ip->i_flag |= IN_CHANGE;
}
/*
* If we successfully wrote any data, and we are not the superuser
diff --git a/sys/ufs/ufs/ufs_dirhash.c b/sys/ufs/ufs/ufs_dirhash.c
index 0eacb58797f2..3b6d5e1fafa5 100644
--- a/sys/ufs/ufs/ufs_dirhash.c
+++ b/sys/ufs/ufs/ufs_dirhash.c
@@ -126,6 +126,18 @@ static struct mtx ufsdirhash_mtx;
* free a dirhash structure that was recycled by ufsdirhash_recycle().
*
* The dirhash lock may be held across io operations.
+ *
+ * WITNESS reports a lock order reversal between the "bufwait" lock
+ * and the "dirhash" lock. However, this specific reversal will not
+ * cause a deadlock. To get a deadlock, one would have to lock a
+ * buffer followed by the dirhash while a second thread locked a
+ * buffer while holding the dirhash lock. The second order can happen
+ * under a shared or exclusive vnode lock for the associated directory
+ * in lookup(). The first order, however, can only happen under an
+ * exclusive vnode lock (e.g. unlink(), rename(), etc.). Thus, for
+ * a thread to be doing a "bufwait" -> "dirhash" order, it has to hold
+ * an exclusive vnode lock. That exclusive vnode lock will prevent
+ * any other threads from doing a "dirhash" -> "bufwait" order.
*/
static void
diff --git a/sys/ufs/ufs/ufs_extattr.c b/sys/ufs/ufs/ufs_extattr.c
index b991920913eb..d034bee1f500 100644
--- a/sys/ufs/ufs/ufs_extattr.c
+++ b/sys/ufs/ufs/ufs_extattr.c
@@ -93,6 +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);
+static int ufs_extattr_autostart_locked(struct mount *mp,
+ struct thread *td);
+static int ufs_extattr_start_locked(struct ufsmount *ump,
+ struct thread *td);
/*
* Per-FS attribute lock protecting attribute operations.
@@ -208,24 +212,22 @@ ufs_extattr_start(struct mount *mp, struct thread *td)
ump = VFSTOUFS(mp);
ufs_extattr_uepm_lock(ump, td);
+ error = ufs_extattr_start_locked(ump, td);
+ ufs_extattr_uepm_unlock(ump, td);
+ return (error);
+}
- if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_INITIALIZED)) {
- error = EOPNOTSUPP;
- goto unlock;
- }
- if (ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED) {
- error = EBUSY;
- goto unlock;
- }
+static int
+ufs_extattr_start_locked(struct ufsmount *ump, struct thread *td)
+{
+ if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_INITIALIZED))
+ return (EOPNOTSUPP);
+ if (ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)
+ return (EBUSY);
ump->um_extattr.uepm_flags |= UFS_EXTATTR_UEPM_STARTED;
-
ump->um_extattr.uepm_ucred = crhold(td->td_ucred);
-
-unlock:
- ufs_extattr_uepm_unlock(ump, td);
-
- return (error);
+ return (0);
}
#ifdef UFS_EXTATTR_AUTOSTART
@@ -448,6 +450,19 @@ ufs_extattr_iterate_directory(struct ufsmount *ump, struct vnode *dvp,
int
ufs_extattr_autostart(struct mount *mp, struct thread *td)
{
+ struct ufsmount *ump;
+ int error;
+
+ ump = VFSTOUFS(mp);
+ ufs_extattr_uepm_lock(ump, td);
+ error = ufs_extattr_autostart_locked(mp, td);
+ ufs_extattr_uepm_unlock(ump, td);
+ return (error);
+}
+
+static int
+ufs_extattr_autostart_locked(struct mount *mp, struct thread *td)
+{
struct vnode *rvp, *attr_dvp, *attr_system_dvp, *attr_user_dvp;
struct ufsmount *ump = VFSTOUFS(mp);
int error;
@@ -491,7 +506,7 @@ ufs_extattr_autostart(struct mount *mp, struct thread *td)
goto return_vput_attr_dvp;
}
- error = ufs_extattr_start(mp, td);
+ error = ufs_extattr_start_locked(ump, td);
if (error) {
printf("ufs_extattr_autostart: ufs_extattr_start failed (%d)\n",
error);
diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c
index 65ab0da10e40..bc11a6a26bef 100644
--- a/sys/ufs/ufs/ufs_lookup.c
+++ b/sys/ufs/ufs/ufs_lookup.c
@@ -157,7 +157,6 @@ ufs_lookup(ap)
int nameiop = cnp->cn_nameiop;
ino_t ino;
int ltype;
- struct mount *mp;
bp = NULL;
slotoffset = -1;
@@ -578,27 +577,7 @@ found:
*/
pdp = vdp;
if (flags & ISDOTDOT) {
- ltype = VOP_ISLOCKED(pdp);
- mp = pdp->v_mount;
- for (;;) {
- error = vfs_busy(mp, MBF_NOWAIT);
- if (error == 0)
- break;
- VOP_UNLOCK(pdp, 0);
- pause("ufs_dd", 1);
- vn_lock(pdp, ltype | LK_RETRY);
- if (pdp->v_iflag & VI_DOOMED)
- return (ENOENT);
- }
- VOP_UNLOCK(pdp, 0); /* race to get the inode */
- error = VFS_VGET(mp, ino, cnp->cn_lkflags, &tdp);
- vfs_unbusy(mp);
- vn_lock(pdp, ltype | LK_RETRY);
- if (pdp->v_iflag & VI_DOOMED) {
- if (error == 0)
- vput(tdp);
- error = ENOENT;
- }
+ error = vn_vget_ino(pdp, ino, cnp->cn_lkflags, &tdp);
if (error)
return (error);
*vpp = tdp;
diff --git a/sys/ufs/ufs/ufs_quota.c b/sys/ufs/ufs/ufs_quota.c
index 2adf7ef8fd7b..ddba6010100f 100644
--- a/sys/ufs/ufs/ufs_quota.c
+++ b/sys/ufs/ufs/ufs_quota.c
@@ -1291,7 +1291,7 @@ hfound: DQI_LOCK(dq);
return (EUSERS);
}
if (dq->dq_cnt || (dq->dq_flags & DQ_MOD))
- panic("dqget: free dquot isn't");
+ panic("dqget: free dquot isn't %p", dq);
TAILQ_REMOVE(&dqfreelist, dq, dq_freelist);
if (dq->dq_ump != NULL)
LIST_REMOVE(dq, dq_hash);
@@ -1434,7 +1434,7 @@ dqrele(struct vnode *vp, struct dquot *dq)
return;
}
DQH_UNLOCK();
-
+sync:
(void) dqsync(vp, dq);
DQH_LOCK();
@@ -1443,6 +1443,18 @@ dqrele(struct vnode *vp, struct dquot *dq)
DQH_UNLOCK();
return;
}
+
+ /*
+ * The dq may become dirty after it is synced but before it is
+ * put to the free list. Checking the DQ_MOD there without
+ * locking dq should be safe since no other references to the
+ * dq exist.
+ */
+ if ((dq->dq_flags & DQ_MOD) != 0) {
+ dq->dq_cnt++;
+ DQH_UNLOCK();
+ goto sync;
+ }
TAILQ_INSERT_TAIL(&dqfreelist, dq, dq_freelist);
DQH_UNLOCK();
}
diff --git a/sys/ufs/ufs/ufs_vfsops.c b/sys/ufs/ufs/ufs_vfsops.c
index 2ddde018f1ae..33b35aff6ab4 100644
--- a/sys/ufs/ufs/ufs_vfsops.c
+++ b/sys/ufs/ufs/ufs_vfsops.c
@@ -118,9 +118,6 @@ ufs_quotactl(mp, cmds, id, arg, td)
if ((u_int)type >= MAXQUOTAS)
return (EINVAL);
- if (vfs_busy(mp, MBF_NOWAIT))
- return (0);
-
switch (cmd) {
case Q_QUOTAON:
error = quotaon(td, mp, type, arg);
@@ -162,7 +159,6 @@ ufs_quotactl(mp, cmds, id, arg, td)
error = EINVAL;
break;
}
- vfs_unbusy(mp);
return (error);
#endif
}
diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c
index e5047e9addbc..675c55cf2006 100644
--- a/sys/ufs/ufs/ufs_vnops.c
+++ b/sys/ufs/ufs/ufs_vnops.c
@@ -98,6 +98,7 @@ static vop_create_t ufs_create;
static vop_getattr_t ufs_getattr;
static vop_link_t ufs_link;
static int ufs_makeinode(int mode, struct vnode *, struct vnode **, struct componentname *);
+static vop_markatime_t ufs_markatime;
static vop_mkdir_t ufs_mkdir;
static vop_mknod_t ufs_mknod;
static vop_open_t ufs_open;
@@ -491,17 +492,6 @@ ufs_setattr(ap)
((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
return (EINVAL);
}
- /*
- * Mark for update the file's access time for vfs_mark_atime().
- * We are doing this here to avoid some of the checks done
- * below -- this operation is done by request of the kernel and
- * should bypass some security checks. Things like read-only
- * checks get handled by other levels (e.g., ffs_update()).
- */
- if (vap->va_vaflags & VA_MARK_ATIME) {
- ip->i_flag |= IN_ACCESS;
- return (0);
- }
if (vap->va_flags != VNOVAL) {
if (vp->v_mount->mnt_flag & MNT_RDONLY)
return (EROFS);
@@ -663,6 +653,25 @@ ufs_setattr(ap)
}
/*
+ * Mark this file's access time for update for vfs_mark_atime(). This
+ * is called from execve() and mmap().
+ */
+static int
+ufs_markatime(ap)
+ struct vop_markatime_args /* {
+ struct vnode *a_vp;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct inode *ip = VTOI(vp);
+
+ VI_LOCK(vp);
+ ip->i_flag |= IN_ACCESS;
+ VI_UNLOCK(vp);
+ return (0);
+}
+
+/*
* Change the mode on a file.
* Inode must be locked before calling.
*/
@@ -2013,7 +2022,7 @@ ufs_strategy(ap)
bp->b_error = error;
bp->b_ioflags |= BIO_ERROR;
bufdone(bp);
- return (error);
+ return (0);
}
if ((long)bp->b_blkno == -1)
vfs_bio_clrbuf(bp);
@@ -2468,6 +2477,7 @@ struct vop_vector ufs_vnodeops = {
.vop_inactive = ufs_inactive,
.vop_link = ufs_link,
.vop_lookup = vfs_cache_lookup,
+ .vop_markatime = ufs_markatime,
.vop_mkdir = ufs_mkdir,
.vop_mknod = ufs_mknod,
.vop_open = ufs_open,
@@ -2507,6 +2517,7 @@ struct vop_vector ufs_fifoops = {
.vop_getattr = ufs_getattr,
.vop_inactive = ufs_inactive,
.vop_kqfilter = ufsfifo_kqfilter,
+ .vop_markatime = ufs_markatime,
.vop_print = ufs_print,
.vop_read = VOP_PANIC,
.vop_reclaim = ufs_reclaim,