diff options
author | Dag-Erling Smørgrav <des@FreeBSD.org> | 2009-09-17 16:16:44 +0000 |
---|---|---|
committer | Dag-Erling Smørgrav <des@FreeBSD.org> | 2009-09-17 16:16:44 +0000 |
commit | 10b3b54548f2290bbe8d8f88c59c28d12b7a635d (patch) | |
tree | dea5b87c905a5175efdc56037f61b7ecb2031d98 /sys/ufs | |
parent | d190eb2e36c4fabd7234d7ece4e44f4b554b35fb (diff) | |
parent | e330a6a59e2df7a34b1ee94602e162b07e4e8a9e (diff) | |
download | src-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.c | 14 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_snapshot.c | 5 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_softdep.c | 61 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_vfsops.c | 64 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_vnops.c | 194 | ||||
-rw-r--r-- | sys/ufs/ufs/dinode.h | 5 | ||||
-rw-r--r-- | sys/ufs/ufs/dirhash.h | 2 | ||||
-rw-r--r-- | sys/ufs/ufs/extattr.h | 2 | ||||
-rw-r--r-- | sys/ufs/ufs/inode.h | 4 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_acl.c | 289 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_dirhash.c | 138 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_extattr.c | 7 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_extern.h | 3 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_lookup.c | 152 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_vfsops.c | 8 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_vnops.c | 81 |
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, |