diff options
author | des <des@FreeBSD.org> | 2010-03-04 13:35:57 +0000 |
---|---|---|
committer | des <des@FreeBSD.org> | 2010-03-04 13:35:57 +0000 |
commit | 834fb25a9ed2240101506d137b5be7d71c75f306 (patch) | |
tree | 4002c72cd1ed11909f7640bea343988cfcf63c5b /sys/ufs | |
parent | 98b742f57cafbed05c101e60cc131f5980f044d0 (diff) | |
parent | 787cf8d03f1c58ada088933408f30fd63de85bf2 (diff) | |
download | FreeBSD-src-834fb25a9ed2240101506d137b5be7d71c75f306.zip FreeBSD-src-834fb25a9ed2240101506d137b5be7d71c75f306.tar.gz |
IFH@204581
Diffstat (limited to 'sys/ufs')
-rw-r--r-- | sys/ufs/ffs/ffs_alloc.c | 206 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_rawread.c | 15 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_snapshot.c | 2 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_vfsops.c | 47 | ||||
-rw-r--r-- | sys/ufs/ffs/fs.h | 91 | ||||
-rw-r--r-- | sys/ufs/ufs/acl.h | 2 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_acl.c | 222 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_dirhash.c | 1 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_lookup.c | 132 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_vnops.c | 533 |
10 files changed, 919 insertions, 332 deletions
diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c index b4f001e..7bf1177 100644 --- a/sys/ufs/ffs/ffs_alloc.c +++ b/sys/ufs/ffs/ffs_alloc.c @@ -69,6 +69,7 @@ __FBSDID("$FreeBSD$"); #include <sys/bio.h> #include <sys/buf.h> #include <sys/conf.h> +#include <sys/fcntl.h> #include <sys/file.h> #include <sys/filedesc.h> #include <sys/priv.h> @@ -76,9 +77,13 @@ __FBSDID("$FreeBSD$"); #include <sys/vnode.h> #include <sys/mount.h> #include <sys/kernel.h> +#include <sys/syscallsubr.h> #include <sys/sysctl.h> #include <sys/syslog.h> +#include <security/audit/audit.h> + +#include <ufs/ufs/dir.h> #include <ufs/ufs/extattr.h> #include <ufs/ufs/quota.h> #include <ufs/ufs/inode.h> @@ -88,24 +93,25 @@ __FBSDID("$FreeBSD$"); #include <ufs/ffs/fs.h> #include <ufs/ffs/ffs_extern.h> -typedef ufs2_daddr_t allocfcn_t(struct inode *ip, int cg, ufs2_daddr_t bpref, +typedef ufs2_daddr_t allocfcn_t(struct inode *ip, u_int cg, ufs2_daddr_t bpref, int size); -static ufs2_daddr_t ffs_alloccg(struct inode *, int, ufs2_daddr_t, int); +static ufs2_daddr_t ffs_alloccg(struct inode *, u_int, ufs2_daddr_t, int); static ufs2_daddr_t ffs_alloccgblk(struct inode *, struct buf *, ufs2_daddr_t); #ifdef INVARIANTS static int ffs_checkblk(struct inode *, ufs2_daddr_t, long); #endif -static ufs2_daddr_t ffs_clusteralloc(struct inode *, int, ufs2_daddr_t, int); +static ufs2_daddr_t ffs_clusteralloc(struct inode *, u_int, ufs2_daddr_t, int); static void ffs_clusteracct(struct ufsmount *, struct fs *, struct cg *, ufs1_daddr_t, int); static ino_t ffs_dirpref(struct inode *); -static ufs2_daddr_t ffs_fragextend(struct inode *, int, ufs2_daddr_t, int, int); +static ufs2_daddr_t ffs_fragextend(struct inode *, u_int, ufs2_daddr_t, + int, int); static void ffs_fserr(struct fs *, ino_t, char *); static ufs2_daddr_t ffs_hashalloc - (struct inode *, int, ufs2_daddr_t, int, allocfcn_t *); -static ufs2_daddr_t ffs_nodealloccg(struct inode *, int, ufs2_daddr_t, int); + (struct inode *, u_int, ufs2_daddr_t, int, allocfcn_t *); +static ufs2_daddr_t ffs_nodealloccg(struct inode *, u_int, ufs2_daddr_t, int); static ufs1_daddr_t ffs_mapsearch(struct fs *, struct cg *, ufs2_daddr_t, int); static int ffs_reallocblks_ufs1(struct vop_reallocblks_args *); static int ffs_reallocblks_ufs2(struct vop_reallocblks_args *); @@ -140,7 +146,7 @@ ffs_alloc(ip, lbn, bpref, size, flags, cred, bnp) struct fs *fs; struct ufsmount *ump; ufs2_daddr_t bno; - int cg, reclaimed; + u_int cg, reclaimed; static struct timeval lastfail; static int curfail; int64_t delta; @@ -243,7 +249,8 @@ ffs_realloccg(ip, lbprev, bprev, bpref, osize, nsize, flags, cred, bpp) struct fs *fs; struct buf *bp; struct ufsmount *ump; - int cg, request, error, reclaimed; + u_int cg, request, reclaimed; + int error; ufs2_daddr_t bno; static struct timeval lastfail; static int curfail; @@ -425,8 +432,10 @@ nospace: reclaimed = 1; softdep_request_cleanup(fs, vp); UFS_UNLOCK(ump); - if (bp) + if (bp) { brelse(bp); + bp = NULL; + } UFS_LOCK(ump); goto retry; } @@ -928,7 +937,8 @@ ffs_valloc(pvp, mode, cred, vpp) struct timespec ts; struct ufsmount *ump; ino_t ino, ipref; - int cg, error, error1; + u_int cg; + int error, error1; static struct timeval lastfail; static int curfail; @@ -1038,11 +1048,11 @@ ffs_dirpref(pip) struct inode *pip; { struct fs *fs; - int cg, prefcg, dirsize, cgsize; - int avgifree, avgbfree, avgndir, curdirsize; - int minifree, minbfree, maxndir; - int mincg, minndir; - int maxcontigdirs; + u_int cg, prefcg, dirsize, cgsize; + u_int avgifree, avgbfree, avgndir, curdirsize; + u_int minifree, minbfree, maxndir; + u_int mincg, minndir; + u_int maxcontigdirs; mtx_assert(UFS_MTX(pip->i_ump), MA_OWNED); fs = pip->i_fs; @@ -1166,8 +1176,8 @@ ffs_blkpref_ufs1(ip, lbn, indx, bap) ufs1_daddr_t *bap; { struct fs *fs; - int cg; - int avgbfree, startcg; + u_int cg; + u_int avgbfree, startcg; mtx_assert(UFS_MTX(ip->i_ump), MA_OWNED); fs = ip->i_fs; @@ -1216,8 +1226,8 @@ ffs_blkpref_ufs2(ip, lbn, indx, bap) ufs2_daddr_t *bap; { struct fs *fs; - int cg; - int avgbfree, startcg; + u_int cg; + u_int avgbfree, startcg; mtx_assert(UFS_MTX(ip->i_ump), MA_OWNED); fs = ip->i_fs; @@ -1270,14 +1280,14 @@ ffs_blkpref_ufs2(ip, lbn, indx, bap) static ufs2_daddr_t ffs_hashalloc(ip, cg, pref, size, allocator) struct inode *ip; - int cg; + u_int cg; ufs2_daddr_t pref; int size; /* size for data blocks, mode for inodes */ allocfcn_t *allocator; { struct fs *fs; ufs2_daddr_t result; - int i, icg = cg; + u_int i, icg = cg; mtx_assert(UFS_MTX(ip->i_ump), MA_OWNED); #ifdef INVARIANTS @@ -1328,7 +1338,7 @@ ffs_hashalloc(ip, cg, pref, size, allocator) static ufs2_daddr_t ffs_fragextend(ip, cg, bprev, osize, nsize) struct inode *ip; - int cg; + u_int cg; ufs2_daddr_t bprev; int osize, nsize; { @@ -1411,7 +1421,7 @@ fail: static ufs2_daddr_t ffs_alloccg(ip, cg, bpref, size) struct inode *ip; - int cg; + u_int cg; ufs2_daddr_t bpref; int size; { @@ -1581,7 +1591,7 @@ gotit: static ufs2_daddr_t ffs_clusteralloc(ip, cg, bpref, len) struct inode *ip; - int cg; + u_int cg; ufs2_daddr_t bpref; int len; { @@ -1705,7 +1715,7 @@ fail: static ufs2_daddr_t ffs_nodealloccg(ip, cg, ipref, mode) struct inode *ip; - int cg; + u_int cg; ufs2_daddr_t ipref; int mode; { @@ -1806,7 +1816,7 @@ gotit: bdwrite(bp); if (ibp != NULL) bawrite(ibp); - return (cg * fs->fs_ipg + ipref); + return ((ino_t)(cg * fs->fs_ipg + ipref)); } /* @@ -1851,7 +1861,8 @@ ffs_blkfree(ump, fs, devvp, bno, size, inum) struct buf *bp; ufs1_daddr_t fragno, cgbno; ufs2_daddr_t cgblkno; - int i, cg, blk, frags, bbase; + int i, blk, frags, bbase; + u_int cg; u_int8_t *blksfree; struct cdev *dev; @@ -2049,7 +2060,8 @@ ffs_freefile(ump, fs, devvp, ino, mode) struct cg *cgp; struct buf *bp; ufs2_daddr_t cgbno; - int error, cg; + int error; + u_int cg; u_int8_t *inosused; struct cdev *dev; @@ -2063,7 +2075,7 @@ ffs_freefile(ump, fs, devvp, ino, mode) dev = devvp->v_rdev; cgbno = fsbtodb(fs, cgtod(fs, cg)); } - if ((u_int)ino >= fs->fs_ipg * fs->fs_ncg) + if (ino >= fs->fs_ipg * fs->fs_ncg) panic("ffs_freefile: range: dev = %s, ino = %lu, fs = %s", devtoname(dev), (u_long)ino, fs->fs_fsmnt); if ((error = bread(devvp, cgbno, (int)fs->fs_cgsize, NOCRED, &bp))) { @@ -2080,8 +2092,8 @@ ffs_freefile(ump, fs, devvp, ino, mode) inosused = cg_inosused(cgp); ino %= fs->fs_ipg; if (isclr(inosused, ino)) { - printf("dev = %s, ino = %lu, fs = %s\n", devtoname(dev), - (u_long)ino + cg * fs->fs_ipg, fs->fs_fsmnt); + printf("dev = %s, ino = %u, fs = %s\n", devtoname(dev), + ino + cg * fs->fs_ipg, fs->fs_fsmnt); if (fs->fs_ronly == 0) panic("ffs_freefile: freeing free inode"); } @@ -2116,7 +2128,8 @@ ffs_checkfreefile(fs, devvp, ino) struct cg *cgp; struct buf *bp; ufs2_daddr_t cgbno; - int ret, cg; + int ret; + u_int cg; u_int8_t *inosused; cg = ino_to_cg(fs, ino); @@ -2127,7 +2140,7 @@ ffs_checkfreefile(fs, devvp, ino) /* devvp is a normal disk device */ cgbno = fsbtodb(fs, cgtod(fs, cg)); } - if ((u_int)ino >= fs->fs_ipg * fs->fs_ncg) + if (ino >= fs->fs_ipg * fs->fs_ncg) return (1); if (bread(devvp, cgbno, (int)fs->fs_cgsize, NOCRED, &bp)) { brelse(bp); @@ -2328,7 +2341,7 @@ ffs_fserr(fs, inum, cp) /* * This function provides the capability for the fsck program to - * update an active filesystem. Eleven operations are provided: + * update an active filesystem. Fourteen operations are provided: * * adjrefcnt(inode, amt) - adjusts the reference count on the * specified inode by the specified amount. Under normal @@ -2349,6 +2362,12 @@ ffs_fserr(fs, inum, cp) * as in use. * setflags(flags, set/clear) - the fs_flags field has the specified * flags set (second parameter +1) or cleared (second parameter -1). + * setcwd(dirinode) - set the current directory to dirinode in the + * filesystem associated with the snapshot. + * setdotdot(oldvalue, newvalue) - Verify that the inode number for ".." + * in the current directory is oldvalue then change it to newvalue. + * unlink(nameptr, oldvalue) - Verify that the inode number associated + * with nameptr in the current directory is oldvalue then unlink it. */ static int sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS); @@ -2386,6 +2405,15 @@ static SYSCTL_NODE(_vfs_ffs, FFS_BLK_FREE, freeblks, CTLFLAG_WR, static SYSCTL_NODE(_vfs_ffs, FFS_SET_FLAGS, setflags, CTLFLAG_WR, sysctl_ffs_fsck, "Change Filesystem Flags"); +static SYSCTL_NODE(_vfs_ffs, FFS_SET_CWD, setcwd, CTLFLAG_WR, + sysctl_ffs_fsck, "Set Current Working Directory"); + +static SYSCTL_NODE(_vfs_ffs, FFS_SET_DOTDOT, setdotdot, CTLFLAG_WR, + sysctl_ffs_fsck, "Change Value of .. Entry"); + +static SYSCTL_NODE(_vfs_ffs, FFS_UNLINK, unlink, CTLFLAG_WR, + sysctl_ffs_fsck, "Unlink a Duplicate Name"); + #ifdef DEBUG static int fsckcmds = 0; SYSCTL_INT(_debug, OID_AUTO, fsckcmds, CTLFLAG_RW, &fsckcmds, 0, ""); @@ -2394,16 +2422,18 @@ SYSCTL_INT(_debug, OID_AUTO, fsckcmds, CTLFLAG_RW, &fsckcmds, 0, ""); static int sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) { + struct thread *td = curthread; struct fsck_cmd cmd; struct ufsmount *ump; - struct vnode *vp; - struct inode *ip; + struct vnode *vp, *vpold, *dvp, *fdvp; + struct inode *ip, *dp; struct mount *mp; struct fs *fs; ufs2_daddr_t blkno; long blkcnt, blksize; + struct filedesc *fdp; struct file *fp; - int filetype, error; + int vfslocked, filetype, error; if (req->newlen > sizeof cmd) return (EBADRPC); @@ -2413,15 +2443,20 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) return (ERPCMISMATCH); if ((error = getvnode(curproc->p_fd, cmd.handle, &fp)) != 0) return (error); - vn_start_write(fp->f_data, &mp, V_WAIT); + vp = fp->f_data; + if (vp->v_type != VREG && vp->v_type != VDIR) { + fdrop(fp, td); + return (EINVAL); + } + vn_start_write(vp, &mp, V_WAIT); if (mp == 0 || strncmp(mp->mnt_stat.f_fstypename, "ufs", MFSNAMELEN)) { vn_finished_write(mp); - fdrop(fp, curthread); + fdrop(fp, td); return (EINVAL); } if (mp->mnt_flag & MNT_RDONLY) { vn_finished_write(mp); - fdrop(fp, curthread); + fdrop(fp, td); return (EROFS); } ump = VFSTOUFS(mp); @@ -2553,6 +2588,7 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) #endif /* DEBUG */ fs->fs_cstotal.cs_ndir += cmd.value; break; + case FFS_ADJ_NBFREE: #ifdef DEBUG if (fsckcmds) { @@ -2562,6 +2598,7 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) #endif /* DEBUG */ fs->fs_cstotal.cs_nbfree += cmd.value; break; + case FFS_ADJ_NIFREE: #ifdef DEBUG if (fsckcmds) { @@ -2571,6 +2608,7 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) #endif /* DEBUG */ fs->fs_cstotal.cs_nifree += cmd.value; break; + case FFS_ADJ_NFFREE: #ifdef DEBUG if (fsckcmds) { @@ -2580,6 +2618,7 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) #endif /* DEBUG */ fs->fs_cstotal.cs_nffree += cmd.value; break; + case FFS_ADJ_NUMCLUSTERS: #ifdef DEBUG if (fsckcmds) { @@ -2590,6 +2629,91 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) fs->fs_cstotal.cs_numclusters += cmd.value; break; + case FFS_SET_CWD: +#ifdef DEBUG + if (fsckcmds) { + printf("%s: set current directory to inode %jd\n", + mp->mnt_stat.f_mntonname, (intmax_t)cmd.value); + } +#endif /* DEBUG */ + if ((error = ffs_vget(mp, (ino_t)cmd.value, LK_SHARED, &vp))) + break; + vfslocked = VFS_LOCK_GIANT(vp->v_mount); + AUDIT_ARG_VNODE1(vp); + if ((error = change_dir(vp, td)) != 0) { + vput(vp); + VFS_UNLOCK_GIANT(vfslocked); + break; + } + VOP_UNLOCK(vp, 0); + VFS_UNLOCK_GIANT(vfslocked); + fdp = td->td_proc->p_fd; + FILEDESC_XLOCK(fdp); + vpold = fdp->fd_cdir; + fdp->fd_cdir = vp; + FILEDESC_XUNLOCK(fdp); + vfslocked = VFS_LOCK_GIANT(vpold->v_mount); + vrele(vpold); + VFS_UNLOCK_GIANT(vfslocked); + break; + + case FFS_SET_DOTDOT: +#ifdef DEBUG + if (fsckcmds) { + printf("%s: change .. in cwd from %jd to %jd\n", + mp->mnt_stat.f_mntonname, (intmax_t)cmd.value, + (intmax_t)cmd.size); + } +#endif /* DEBUG */ + /* + * First we have to get and lock the parent directory + * to which ".." points. + */ + error = ffs_vget(mp, (ino_t)cmd.value, LK_EXCLUSIVE, &fdvp); + if (error) + break; + /* + * Now we get and lock the child directory containing "..". + */ + FILEDESC_SLOCK(td->td_proc->p_fd); + dvp = td->td_proc->p_fd->fd_cdir; + FILEDESC_SUNLOCK(td->td_proc->p_fd); + if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) { + vput(fdvp); + break; + } + dp = VTOI(dvp); + dp->i_offset = 12; /* XXX mastertemplate.dot_reclen */ + error = ufs_dirrewrite(dp, VTOI(fdvp), (ino_t)cmd.size, + DT_DIR, 0); + cache_purge(fdvp); + cache_purge(dvp); + vput(dvp); + vput(fdvp); + break; + + case FFS_UNLINK: +#ifdef DEBUG + if (fsckcmds) { + char buf[32]; + + if (copyinstr((char *)(intptr_t)cmd.value, buf,32,NULL)) + strncpy(buf, "Name_too_long", 32); + printf("%s: unlink %s (inode %jd)\n", + mp->mnt_stat.f_mntonname, buf, (intmax_t)cmd.size); + } +#endif /* DEBUG */ + /* + * kern_unlinkat will do its own start/finish writes and + * they do not nest, so drop ours here. Setting mp == NULL + * indicates that vn_finished_write is not needed down below. + */ + vn_finished_write(mp); + mp = NULL; + error = kern_unlinkat(td, AT_FDCWD, (char *)(intptr_t)cmd.value, + UIO_USERSPACE, (ino_t)cmd.size); + break; + default: #ifdef DEBUG if (fsckcmds) { @@ -2601,7 +2725,7 @@ sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) break; } - fdrop(fp, curthread); + fdrop(fp, td); vn_finished_write(mp); return (error); } diff --git a/sys/ufs/ffs/ffs_rawread.c b/sys/ufs/ffs/ffs_rawread.c index 434c833..574d89c 100644 --- a/sys/ufs/ffs/ffs_rawread.c +++ b/sys/ufs/ffs/ffs_rawread.c @@ -101,6 +101,7 @@ ffs_rawread_sync(struct vnode *vp) int upgraded; struct bufobj *bo; struct mount *mp; + vm_object_t obj; /* Check for dirty mmap, pending writes and dirty buffers */ bo = &vp->v_bufobj; @@ -108,7 +109,8 @@ ffs_rawread_sync(struct vnode *vp) VI_LOCK(vp); if (bo->bo_numoutput > 0 || bo->bo_dirty.bv_cnt > 0 || - (vp->v_iflag & VI_OBJDIRTY) != 0) { + ((obj = vp->v_object) != NULL && + (obj->flags & OBJ_MIGHTBEDIRTY) != 0)) { VI_UNLOCK(vp); BO_UNLOCK(bo); @@ -138,13 +140,12 @@ ffs_rawread_sync(struct vnode *vp) return (EIO); } /* Attempt to msync mmap() regions to clean dirty mmap */ - if ((vp->v_iflag & VI_OBJDIRTY) != 0) { + if ((obj = vp->v_object) != NULL && + (obj->flags & OBJ_MIGHTBEDIRTY) != 0) { VI_UNLOCK(vp); - if (vp->v_object != NULL) { - VM_OBJECT_LOCK(vp->v_object); - vm_object_page_clean(vp->v_object, 0, 0, OBJPC_SYNC); - VM_OBJECT_UNLOCK(vp->v_object); - } + VM_OBJECT_LOCK(obj); + vm_object_page_clean(obj, 0, 0, OBJPC_SYNC); + VM_OBJECT_UNLOCK(obj); } else VI_UNLOCK(vp); diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c index a6e73f5..b36cb58 100644 --- a/sys/ufs/ffs/ffs_snapshot.c +++ b/sys/ufs/ffs/ffs_snapshot.c @@ -739,7 +739,7 @@ out1: auio.uio_iovcnt = 1; aiov.iov_base = (void *)snapblklist; aiov.iov_len = snaplistsize * sizeof(daddr_t); - auio.uio_resid = aiov.iov_len;; + auio.uio_resid = aiov.iov_len; auio.uio_offset = ip->i_size; auio.uio_segflg = UIO_SYSSPACE; auio.uio_rw = UIO_WRITE; diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index d3d7c2c..8aa9f9c 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -128,7 +128,7 @@ static struct buf_ops ffs_ops = { static const char *ffs_opts[] = { "acls", "async", "noatime", "noclusterr", "noclusterw", "noexec", "export", "force", "from", "multilabel", "snapshot", "nosuid", "suiddir", "nosymfollow", "sync", - "union", NULL }; + "union", "nfsv4acls", NULL }; static int ffs_mount(struct mount *mp) @@ -138,7 +138,7 @@ ffs_mount(struct mount *mp) struct ufsmount *ump = 0; struct fs *fs; int error, flags; - u_int mntorflags, mntandnotflags; + u_int mntorflags; accmode_t accmode; struct nameidata ndp; char *fspec; @@ -163,7 +163,6 @@ ffs_mount(struct mount *mp) return (error); mntorflags = 0; - mntandnotflags = 0; if (vfs_getopt(mp->mnt_optnew, "acls", NULL, NULL) == 0) mntorflags |= MNT_ACLS; @@ -177,8 +176,17 @@ ffs_mount(struct mount *mp) vfs_deleteopt(mp->mnt_opt, "snapshot"); } + if (vfs_getopt(mp->mnt_optnew, "nfsv4acls", NULL, NULL) == 0) { + if (mntorflags & MNT_ACLS) { + printf("WARNING: \"acls\" and \"nfsv4acls\" " + "options are mutually exclusive\n"); + return (EINVAL); + } + mntorflags |= MNT_NFS4ACLS; + } + MNT_ILOCK(mp); - mp->mnt_flag = (mp->mnt_flag | mntorflags) & ~mntandnotflags; + mp->mnt_flag |= mntorflags; MNT_IUNLOCK(mp); /* * If updating, check whether changing from read-only to @@ -360,6 +368,13 @@ ffs_mount(struct mount *mp) MNT_IUNLOCK(mp); } + if ((fs->fs_flags & FS_NFS4ACLS) != 0) { + /* XXX: Set too late ? */ + MNT_ILOCK(mp); + mp->mnt_flag |= MNT_NFS4ACLS; + MNT_IUNLOCK(mp); + } + /* * If this is a snapshot request, take the snapshot. */ @@ -834,7 +849,13 @@ ffs_mountfs(devvp, mp, td) if ((fs->fs_flags & FS_ACLS) != 0) { #ifdef UFS_ACL MNT_ILOCK(mp); + + if (mp->mnt_flag & MNT_NFS4ACLS) + printf("WARNING: ACLs flag on fs conflicts with " + "\"nfsv4acls\" mount option; option ignored\n"); + mp->mnt_flag &= ~MNT_NFS4ACLS; mp->mnt_flag |= MNT_ACLS; + MNT_IUNLOCK(mp); #else printf( @@ -842,6 +863,24 @@ ffs_mountfs(devvp, mp, td) mp->mnt_stat.f_mntonname); #endif } + if ((fs->fs_flags & FS_NFS4ACLS) != 0) { +#ifdef UFS_ACL + MNT_ILOCK(mp); + + if (mp->mnt_flag & MNT_ACLS) + printf("WARNING: NFSv4 ACLs flag on fs conflicts with " + "\"acls\" mount option; option ignored\n"); + mp->mnt_flag &= ~MNT_ACLS; + mp->mnt_flag |= MNT_NFS4ACLS; + + MNT_IUNLOCK(mp); +#else + printf( +"WARNING: %s: NFSv4 ACLs flag on fs but no ACLs support\n", + mp->mnt_stat.f_mntonname); +#endif + } + ump->um_mountp = mp; ump->um_dev = dev; ump->um_devvp = devvp; diff --git a/sys/ufs/ffs/fs.h b/sys/ufs/ffs/fs.h index 7da18ea..5452e2b 100644 --- a/sys/ufs/ffs/fs.h +++ b/sys/ufs/ffs/fs.h @@ -211,7 +211,10 @@ #define FFS_ADJ_NIFREE 9 /* adjust number of free inodes */ #define FFS_ADJ_NFFREE 10 /* adjust number of free frags */ #define FFS_ADJ_NUMCLUSTERS 11 /* adjust number of free clusters */ -#define FFS_MAXID 12 /* number of valid ffs ids */ +#define FFS_SET_CWD 12 /* set current directory */ +#define FFS_SET_DOTDOT 13 /* set inode number for ".." */ +#define FFS_UNLINK 14 /* remove a name in the filesystem */ +#define FFS_MAXID 15 /* number of valid ffs ids */ /* * Command structure passed in to the filesystem to adjust filesystem values. @@ -261,7 +264,7 @@ struct fs { int32_t fs_old_time; /* last time written */ int32_t fs_old_size; /* number of blocks in fs */ int32_t fs_old_dsize; /* number of data blocks in fs */ - int32_t fs_ncg; /* number of cylinder groups */ + u_int32_t fs_ncg; /* number of cylinder groups */ int32_t fs_bsize; /* size of basic blocks in fs */ int32_t fs_fsize; /* size of frag blocks in fs */ int32_t fs_frag; /* number of frags in a block in fs */ @@ -284,7 +287,7 @@ struct fs { int32_t fs_spare1[2]; /* old fs_csmask */ /* old fs_csshift */ int32_t fs_nindir; /* value of NINDIR */ - int32_t fs_inopb; /* value of INOPB */ + u_int32_t fs_inopb; /* value of INOPB */ int32_t fs_old_nspf; /* value of NSPF */ /* yet another configuration parameter */ int32_t fs_optim; /* optimization preference, see below */ @@ -301,7 +304,7 @@ struct fs { int32_t fs_old_spc; /* sectors per cylinder */ int32_t fs_old_ncyl; /* cylinders in filesystem */ int32_t fs_old_cpg; /* cylinders per group */ - int32_t fs_ipg; /* inodes per group */ + u_int32_t fs_ipg; /* inodes per group */ int32_t fs_fpg; /* blocks per group * fs_frag */ /* this data must be re-computed after crashes */ struct csum fs_old_cstotal; /* cylinder summary information */ @@ -332,10 +335,10 @@ struct fs { int64_t fs_dsize; /* number of data blocks in fs */ ufs2_daddr_t fs_csaddr; /* blk addr of cyl grp summary area */ int64_t fs_pendingblocks; /* (u) blocks being freed */ - int32_t fs_pendinginodes; /* (u) inodes being freed */ - int32_t fs_snapinum[FSMAXSNAP];/* list of snapshot inode numbers */ - int32_t fs_avgfilesize; /* expected average file size */ - int32_t fs_avgfpdir; /* expected # of files per directory */ + u_int32_t fs_pendinginodes; /* (u) inodes being freed */ + ino_t fs_snapinum[FSMAXSNAP];/* list of snapshot inode numbers */ + u_int32_t fs_avgfilesize; /* expected average file size */ + u_int32_t fs_avgfpdir; /* expected # of files per directory */ int32_t fs_save_cgsize; /* save real cg size to use fs_bsize */ int32_t fs_sparecon32[26]; /* reserved for future constants */ int32_t fs_flags; /* see FS_ flags below */ @@ -393,22 +396,24 @@ CTASSERT(sizeof(struct fs) == 1376); * flag to indicate that the indicies need to be rebuilt (by fsck) before * they can be used. * - * FS_ACLS indicates that ACLs are administratively enabled for the - * file system, so they should be loaded from extended attributes, + * FS_ACLS indicates that POSIX.1e ACLs are administratively enabled + * for the file system, so they should be loaded from extended attributes, * observed for access control purposes, and be administered by object - * owners. FS_MULTILABEL indicates that the TrustedBSD MAC Framework - * should attempt to back MAC labels into extended attributes on the - * file system rather than maintain a single mount label for all - * objects. - */ -#define FS_UNCLEAN 0x01 /* filesystem not clean at mount */ -#define FS_DOSOFTDEP 0x02 /* filesystem using soft dependencies */ -#define FS_NEEDSFSCK 0x04 /* filesystem needs sync fsck before mount */ -#define FS_INDEXDIRS 0x08 /* kernel supports indexed directories */ -#define FS_ACLS 0x10 /* file system has ACLs enabled */ -#define FS_MULTILABEL 0x20 /* file system is MAC multi-label */ -#define FS_GJOURNAL 0x40 /* gjournaled file system */ -#define FS_FLAGS_UPDATED 0x80 /* flags have been moved to new location */ + * owners. FS_NFS4ACLS indicates that NFSv4 ACLs are administratively + * enabled. This flag is mutually exclusive with FS_ACLS. FS_MULTILABEL + * indicates that the TrustedBSD MAC Framework should attempt to back MAC + * labels into extended attributes on the file system rather than maintain + * a single mount label for all objects. + */ +#define FS_UNCLEAN 0x0001 /* filesystem not clean at mount */ +#define FS_DOSOFTDEP 0x0002 /* filesystem using soft dependencies */ +#define FS_NEEDSFSCK 0x0004 /* filesystem needs sync fsck before mount */ +#define FS_INDEXDIRS 0x0008 /* kernel supports indexed directories */ +#define FS_ACLS 0x0010 /* file system has POSIX.1e ACLs enabled */ +#define FS_MULTILABEL 0x0020 /* file system is MAC multi-label */ +#define FS_GJOURNAL 0x0040 /* gjournaled file system */ +#define FS_FLAGS_UPDATED 0x0080 /* flags have been moved to new location */ +#define FS_NFS4ACLS 0x0100 /* file system has NFSv4 ACLs enabled */ /* * Macros to access bits in the fs_active array. @@ -458,26 +463,26 @@ struct cg { int32_t cg_firstfield; /* historic cyl groups linked list */ int32_t cg_magic; /* magic number */ int32_t cg_old_time; /* time last written */ - int32_t cg_cgx; /* we are the cgx'th cylinder group */ + u_int32_t cg_cgx; /* we are the cgx'th cylinder group */ int16_t cg_old_ncyl; /* number of cyl's this cg */ int16_t cg_old_niblk; /* number of inode blocks this cg */ - int32_t cg_ndblk; /* number of data blocks this cg */ - struct csum cg_cs; /* cylinder summary information */ - int32_t cg_rotor; /* position of last used block */ - int32_t cg_frotor; /* position of last used frag */ - int32_t cg_irotor; /* position of last used inode */ - int32_t cg_frsum[MAXFRAG]; /* counts of available frags */ + u_int32_t cg_ndblk; /* number of data blocks this cg */ + struct csum cg_cs; /* cylinder summary information */ + u_int32_t cg_rotor; /* position of last used block */ + u_int32_t cg_frotor; /* position of last used frag */ + u_int32_t cg_irotor; /* position of last used inode */ + u_int32_t cg_frsum[MAXFRAG]; /* counts of available frags */ int32_t cg_old_btotoff; /* (int32) block totals per cylinder */ int32_t cg_old_boff; /* (u_int16) free block positions */ - int32_t cg_iusedoff; /* (u_int8) used inode map */ - int32_t cg_freeoff; /* (u_int8) free block map */ - int32_t cg_nextfreeoff; /* (u_int8) next available space */ - int32_t cg_clustersumoff; /* (u_int32) counts of avail clusters */ - int32_t cg_clusteroff; /* (u_int8) free cluster map */ - int32_t cg_nclusterblks; /* number of clusters this cg */ - int32_t cg_niblk; /* number of inode blocks this cg */ - int32_t cg_initediblk; /* last initialized inode */ - int32_t cg_unrefs; /* number of unreferenced inodes */ + u_int32_t cg_iusedoff; /* (u_int8) used inode map */ + u_int32_t cg_freeoff; /* (u_int8) free block map */ + u_int32_t cg_nextfreeoff; /* (u_int8) next available space */ + u_int32_t cg_clustersumoff; /* (u_int32) counts of avail clusters */ + u_int32_t cg_clusteroff; /* (u_int8) free cluster map */ + u_int32_t cg_nclusterblks; /* number of clusters this cg */ + u_int32_t cg_niblk; /* number of inode blocks this cg */ + u_int32_t cg_initediblk; /* last initialized inode */ + u_int32_t cg_unrefs; /* number of unreferenced inodes */ int32_t cg_sparecon32[2]; /* reserved for future use */ ufs_time_t cg_time; /* time last written */ int64_t cg_sparecon64[3]; /* reserved for future use */ @@ -524,11 +529,11 @@ struct cg { * inode number to cylinder group number. * inode number to filesystem block address. */ -#define ino_to_cg(fs, x) ((x) / (fs)->fs_ipg) +#define ino_to_cg(fs, x) (((ino_t)(x)) / (fs)->fs_ipg) #define ino_to_fsba(fs, x) \ - ((ufs2_daddr_t)(cgimin(fs, ino_to_cg(fs, x)) + \ - (blkstofrags((fs), (((x) % (fs)->fs_ipg) / INOPB(fs)))))) -#define ino_to_fsbo(fs, x) ((x) % INOPB(fs)) + ((ufs2_daddr_t)(cgimin(fs, ino_to_cg(fs, (ino_t)(x))) + \ + (blkstofrags((fs), ((((ino_t)(x)) % (fs)->fs_ipg) / INOPB(fs)))))) +#define ino_to_fsbo(fs, x) (((ino_t)(x)) % INOPB(fs)) /* * Give cylinder group number for a filesystem block. diff --git a/sys/ufs/ufs/acl.h b/sys/ufs/ufs/acl.h index b53e328..235261e 100644 --- a/sys/ufs/ufs/acl.h +++ b/sys/ufs/ufs/acl.h @@ -37,6 +37,8 @@ #ifdef _KERNEL +int ufs_getacl_nfs4_internal(struct vnode *vp, struct acl *aclp, struct thread *td); +int ufs_setacl_nfs4_internal(struct vnode *vp, struct acl *aclp, struct thread *td); void ufs_sync_acl_from_inode(struct inode *ip, struct acl *acl); void ufs_sync_inode_from_acl(struct acl *acl, struct inode *ip); diff --git a/sys/ufs/ufs/ufs_acl.c b/sys/ufs/ufs/ufs_acl.c index 68e5015..8ed1c0b 100644 --- a/sys/ufs/ufs/ufs_acl.c +++ b/sys/ufs/ufs/ufs_acl.c @@ -141,6 +141,81 @@ ufs_sync_inode_from_acl(struct acl *acl, struct inode *ip) } /* + * Retrieve NFSv4 ACL, skipping access checks. Must be used in UFS code + * instead of VOP_GETACL() when we don't want to be restricted by the user + * not having ACL_READ_ACL permission, e.g. when calculating inherited ACL + * or in ufs_vnops.c:ufs_accessx(). + */ +int +ufs_getacl_nfs4_internal(struct vnode *vp, struct acl *aclp, struct thread *td) +{ + int error, len; + struct inode *ip = VTOI(vp); + + len = sizeof(*aclp); + bzero(aclp, len); + + error = vn_extattr_get(vp, IO_NODELOCKED, + NFS4_ACL_EXTATTR_NAMESPACE, NFS4_ACL_EXTATTR_NAME, + &len, (char *) aclp, td); + aclp->acl_maxcnt = ACL_MAX_ENTRIES; + if (error == ENOATTR) { + /* + * Legitimately no ACL set on object, purely + * emulate it through the inode. + */ + acl_nfs4_sync_acl_from_mode(aclp, ip->i_mode, ip->i_uid); + + return (0); + } + + if (error) + return (error); + + if (len != sizeof(*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_nfs4(): Loaded invalid ACL (" + "%d bytes), inumber %d on %s\n", len, + ip->i_number, ip->i_fs->fs_fsmnt); + + return (EPERM); + } + + error = acl_nfs4_check(aclp, vp->v_type == VDIR); + if (error) { + printf("ufs_getacl_nfs4(): Loaded invalid ACL " + "(failed acl_nfs4_check), inumber %d on %s\n", + ip->i_number, ip->i_fs->fs_fsmnt); + + return (EPERM); + } + + return (0); +} + +static int +ufs_getacl_nfs4(struct vop_getacl_args *ap) +{ + int error; + + if ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) == 0) + return (EINVAL); + + error = VOP_ACCESSX(ap->a_vp, VREAD_ACL, ap->a_td->td_ucred, ap->a_td); + if (error) + return (error); + + error = ufs_getacl_nfs4_internal(ap->a_vp, ap->a_aclp, ap->a_td); + + return (error); +} + +/* * Read POSIX.1e ACL from an EA. Return error if its not found * or if any other error has occured. */ @@ -209,7 +284,7 @@ ufs_getacl_posix1e(struct vop_getacl_args *ap) * ACLs, remove this check. */ if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0) - return (EOPNOTSUPP); + return (EINVAL); old = malloc(sizeof(*old), M_ACL, M_WAITOK | M_ZERO); @@ -282,10 +357,118 @@ ufs_getacl(ap) } */ *ap; { + if ((ap->a_vp->v_mount->mnt_flag & (MNT_ACLS | MNT_NFS4ACLS)) == 0) + return (EOPNOTSUPP); + + if (ap->a_type == ACL_TYPE_NFS4) + return (ufs_getacl_nfs4(ap)); + return (ufs_getacl_posix1e(ap)); } /* + * Set NFSv4 ACL without doing any access checking. This is required + * e.g. by the UFS code that implements ACL inheritance, or from + * ufs_vnops.c:ufs_chmod(), as some of the checks have to be skipped + * in that case, and others are redundant. + */ +int +ufs_setacl_nfs4_internal(struct vnode *vp, struct acl *aclp, struct thread *td) +{ + int error; + mode_t mode; + struct inode *ip = VTOI(vp); + + KASSERT(acl_nfs4_check(aclp, vp->v_type == VDIR) == 0, + ("invalid ACL passed to ufs_setacl_nfs4_internal")); + + if (acl_nfs4_is_trivial(aclp, ip->i_uid)) { + error = vn_extattr_rm(vp, IO_NODELOCKED, + NFS4_ACL_EXTATTR_NAMESPACE, NFS4_ACL_EXTATTR_NAME, td); + + /* + * An attempt to remove ACL from a file that didn't have + * any extended entries is not an error. + */ + if (error == ENOATTR) + error = 0; + + } else { + error = vn_extattr_set(vp, IO_NODELOCKED, + NFS4_ACL_EXTATTR_NAMESPACE, NFS4_ACL_EXTATTR_NAME, + sizeof(*aclp), (char *) aclp, td); + } + + /* + * Map lack of attribute definition in UFS_EXTATTR into lack of + * support for ACLs on the filesystem. + */ + if (error == ENOATTR) + return (EOPNOTSUPP); + + if (error) + return (error); + + mode = ip->i_mode; + + acl_nfs4_sync_mode_from_acl(&mode, aclp); + + ip->i_mode &= ACL_PRESERVE_MASK; + ip->i_mode |= mode; + DIP_SET(ip, i_mode, ip->i_mode); + ip->i_flag |= IN_CHANGE; + + VN_KNOTE_UNLOCKED(vp, NOTE_ATTRIB); + + return (0); +} + +static int +ufs_setacl_nfs4(struct vop_setacl_args *ap) +{ + int error; + struct inode *ip = VTOI(ap->a_vp); + + if ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) == 0) + return (EINVAL); + + if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + + if (ap->a_aclp == NULL) + return (EINVAL); + + error = VOP_ACLCHECK(ap->a_vp, ap->a_type, ap->a_aclp, ap->a_cred, + ap->a_td); + if (error) + return (error); + + /* + * Authorize the ACL operation. + */ + if (ip->i_flags & (IMMUTABLE | APPEND)) + return (EPERM); + + /* + * Must hold VWRITE_ACL or have appropriate privilege. + */ + if ((error = VOP_ACCESSX(ap->a_vp, VWRITE_ACL, ap->a_cred, ap->a_td))) + return (error); + + /* + * With NFSv4 ACLs, chmod(2) may need to add additional entries. + * Make sure it has enough room for that - splitting every entry + * into two and appending "canonical six" entries at the end. + */ + if (ap->a_aclp->acl_cnt > (ACL_MAX_ENTRIES - 6) / 2) + return (ENOSPC); + + error = ufs_setacl_nfs4_internal(ap->a_vp, ap->a_aclp, ap->a_td); + + return (error); +} + +/* * Set the ACL on a file. * * As part of the ACL is stored in the inode, and the rest in an EA, @@ -302,7 +485,7 @@ ufs_setacl_posix1e(struct vop_setacl_args *ap) struct oldacl *old; if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0) - return (EOPNOTSUPP); + return (EINVAL); /* * If this is a set operation rather than a delete operation, @@ -422,16 +605,43 @@ ufs_setacl(ap) struct thread *td; } */ *ap; { + if ((ap->a_vp->v_mount->mnt_flag & (MNT_ACLS | MNT_NFS4ACLS)) == 0) + return (EOPNOTSUPP); + + if (ap->a_type == ACL_TYPE_NFS4) + return (ufs_setacl_nfs4(ap)); return (ufs_setacl_posix1e(ap)); } static int +ufs_aclcheck_nfs4(struct vop_aclcheck_args *ap) +{ + int is_directory = 0; + + if ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) == 0) + return (EINVAL); + + /* + * With NFSv4 ACLs, chmod(2) may need to add additional entries. + * Make sure it has enough room for that - splitting every entry + * into two and appending "canonical six" entries at the end. + */ + if (ap->a_aclp->acl_cnt > (ACL_MAX_ENTRIES - 6) / 2) + return (ENOSPC); + + if (ap->a_vp->v_type == VDIR) + is_directory = 1; + + return (acl_nfs4_check(ap->a_aclp, is_directory)); +} + +static int ufs_aclcheck_posix1e(struct vop_aclcheck_args *ap) { if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0) - return (EOPNOTSUPP); + return (EINVAL); /* * Verify we understand this type of ACL, and that it applies @@ -471,6 +681,12 @@ ufs_aclcheck(ap) } */ *ap; { + if ((ap->a_vp->v_mount->mnt_flag & (MNT_ACLS | MNT_NFS4ACLS)) == 0) + return (EOPNOTSUPP); + + if (ap->a_type == ACL_TYPE_NFS4) + return (ufs_aclcheck_nfs4(ap)); + return (ufs_aclcheck_posix1e(ap)); } diff --git a/sys/ufs/ufs/ufs_dirhash.c b/sys/ufs/ufs/ufs_dirhash.c index e18b838..c85fdc8 100644 --- a/sys/ufs/ufs/ufs_dirhash.c +++ b/sys/ufs/ufs/ufs_dirhash.c @@ -632,6 +632,7 @@ restart: goto fail; } } + KASSERT(bp != NULL, ("no buffer allocated")); dp = (struct direct *)(bp->b_data + (offset & bmask)); if (dp->d_reclen == 0 || dp->d_reclen > DIRBLKSIZ - (offset & (DIRBLKSIZ - 1))) { diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c index ea73b1f..b0247e7 100644 --- a/sys/ufs/ufs/ufs_lookup.c +++ b/sys/ufs/ufs/ufs_lookup.c @@ -80,6 +80,61 @@ SYSCTL_INT(_debug, OID_AUTO, dircheck, CTLFLAG_RW, &dirchk, 0, ""); static int ufs_lookup_(struct vnode *, struct vnode **, struct componentname *, ino_t *); +static int +ufs_delete_denied(struct vnode *vdp, struct vnode *tdp, struct ucred *cred, + struct thread *td) +{ + int error; + +#ifdef UFS_ACL + /* + * NFSv4 Minor Version 1, draft-ietf-nfsv4-minorversion1-03.txt + * + * 3.16.2.1. ACE4_DELETE vs. ACE4_DELETE_CHILD + */ + + /* + * XXX: Is this check required? + */ + error = VOP_ACCESS(vdp, VEXEC, cred, td); + if (error) + return (error); + + error = VOP_ACCESSX(tdp, VDELETE, cred, td); + if (error == 0) + return (0); + + error = VOP_ACCESSX(vdp, VDELETE_CHILD, cred, td); + if (error == 0) + return (0); + + error = VOP_ACCESSX(vdp, VEXPLICIT_DENY | VDELETE_CHILD, cred, td); + if (error) + return (error); + +#endif /* !UFS_ACL */ + + /* + * Standard Unix access control - delete access requires VWRITE. + */ + error = VOP_ACCESS(vdp, VWRITE, cred, td); + if (error) + return (error); + + /* + * If directory is "sticky", then user must own + * the directory, or the file in it, else she + * may not delete it (unless she's root). This + * implements append-only directories. + */ + if ((VTOI(vdp)->i_mode & ISVTX) && + VOP_ACCESS(vdp, VADMIN, cred, td) && + VOP_ACCESS(tdp, VADMIN, cred, td)) + return (EPERM); + + return (0); +} + /* * Convert a component of a pathname into a pointer to a locked inode. * This is a very central and rather complicated routine. @@ -410,8 +465,13 @@ notfound: /* * Access for write is interpreted as allowing * creation of files in the directory. + * + * XXX: Fix the comment above. */ - error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_thread); + if (flags & WILLBEDIR) + error = VOP_ACCESSX(vdp, VWRITE | VAPPEND, cred, cnp->cn_thread); + else + error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_thread); if (error) return (error); /* @@ -498,12 +558,17 @@ found: if (nameiop == DELETE && (flags & ISLASTCN)) { if (flags & LOCKPARENT) ASSERT_VOP_ELOCKED(vdp, __FUNCTION__); - /* - * Write access to directory required to delete files. - */ - error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_thread); - if (error) + if ((error = VFS_VGET(vdp->v_mount, ino, + LK_EXCLUSIVE, &tdp)) != 0) + return (error); + + error = ufs_delete_denied(vdp, tdp, cred, cnp->cn_thread); + if (error) { + vput(tdp); return (error); + } + + /* * Return pointer to current entry in dp->i_offset, * and distance past previous entry (if there @@ -523,23 +588,10 @@ found: if (dp->i_number == ino) { VREF(vdp); *vpp = vdp; - return (0); - } - if ((error = VFS_VGET(vdp->v_mount, ino, - LK_EXCLUSIVE, &tdp)) != 0) - return (error); - /* - * If directory is "sticky", then user must own - * the directory, or the file in it, else she - * may not delete it (unless she's root). This - * implements append-only directories. - */ - if ((dp->i_mode & ISVTX) && - VOP_ACCESS(vdp, VADMIN, cred, cnp->cn_thread) && - VOP_ACCESS(tdp, VADMIN, cred, cnp->cn_thread)) { vput(tdp); - return (EPERM); + return (0); } + *vpp = tdp; return (0); } @@ -551,7 +603,11 @@ found: * regular file, or empty directory. */ if (nameiop == RENAME && (flags & ISLASTCN)) { - if ((error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_thread))) + if (flags & WILLBEDIR) + error = VOP_ACCESSX(vdp, VWRITE | VAPPEND, cred, cnp->cn_thread); + else + error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_thread); + if (error) return (error); /* * Careful about locking second inode. @@ -563,6 +619,33 @@ found: if ((error = VFS_VGET(vdp->v_mount, ino, LK_EXCLUSIVE, &tdp)) != 0) return (error); + + error = ufs_delete_denied(vdp, tdp, cred, cnp->cn_thread); + if (error) { + vput(tdp); + return (error); + } + +#ifdef SunOS_doesnt_do_that + /* + * The only purpose of this check is to return the correct + * error. Assume that we want to rename directory "a" + * to a file "b", and that we have no ACL_WRITE_DATA on + * a containing directory, but we _do_ have ACL_APPEND_DATA. + * In that case, the VOP_ACCESS check above will return 0, + * and the operation will fail with ENOTDIR instead + * of EACCESS. + */ + if (tdp->v_type == VDIR) + error = VOP_ACCESSX(vdp, VWRITE | VAPPEND, cred, cnp->cn_thread); + else + error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_thread); + if (error) { + vput(tdp); + return (error); + } +#endif + *vpp = tdp; cnp->cn_flags |= SAVENAME; return (0); @@ -1141,6 +1224,11 @@ ufs_dirrewrite(dp, oip, newinum, newtype, isrmdir) error = UFS_BLKATOFF(vdp, (off_t)dp->i_offset, (char **)&ep, &bp); if (error) return (error); + if (ep->d_namlen == 2 && ep->d_name[1] == '.' && ep->d_name[0] == '.' && + ep->d_ino != oip->i_number) { + brelse(bp); + return (EIDRM); + } ep->d_ino = newinum; if (!OFSFMT(vdp)) ep->d_type = newtype; diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c index 08b77ae..9d4d93d 100644 --- a/sys/ufs/ufs/ufs_vnops.c +++ b/sys/ufs/ufs/ufs_vnops.c @@ -88,7 +88,7 @@ __FBSDID("$FreeBSD$"); #include <ufs/ffs/ffs_extern.h> -static vop_access_t ufs_access; +static vop_accessx_t ufs_accessx; static int ufs_chmod(struct vnode *, int, struct ucred *, struct thread *); static int ufs_chown(struct vnode *, uid_t, gid_t, struct ucred *, struct thread *); static vop_close_t ufs_close; @@ -298,8 +298,8 @@ ufs_close(ap) } static int -ufs_access(ap) - struct vop_access_args /* { +ufs_accessx(ap) + struct vop_accessx_args /* { struct vnode *a_vp; accmode_t a_accmode; struct ucred *a_cred; @@ -315,6 +315,7 @@ ufs_access(ap) #endif #ifdef UFS_ACL struct acl *acl; + acl_type_t type; #endif /* @@ -322,7 +323,7 @@ ufs_access(ap) * unless the file is a socket, fifo, or a block or * character device resident on the filesystem. */ - if (accmode & VWRITE) { + if (accmode & VMODIFY_PERMS) { switch (vp->v_type) { case VDIR: case VLNK: @@ -367,41 +368,63 @@ relock: } } - /* If immutable bit set, nobody gets to write it. */ - if ((accmode & VWRITE) && (ip->i_flags & (IMMUTABLE | SF_SNAPSHOT))) + /* + * If immutable bit set, nobody gets to write it. "& ~VADMIN_PERMS" + * is here, because without it, * it would be impossible for the owner + * to remove the IMMUTABLE flag. + */ + if ((accmode & (VMODIFY_PERMS & ~VADMIN_PERMS)) && + (ip->i_flags & (IMMUTABLE | SF_SNAPSHOT))) return (EPERM); #ifdef UFS_ACL - if ((vp->v_mount->mnt_flag & MNT_ACLS) != 0) { + if ((vp->v_mount->mnt_flag & (MNT_ACLS | MNT_NFS4ACLS)) != 0) { + if (vp->v_mount->mnt_flag & MNT_NFS4ACLS) + type = ACL_TYPE_NFS4; + else + type = ACL_TYPE_ACCESS; + acl = acl_alloc(M_WAITOK); - error = VOP_GETACL(vp, ACL_TYPE_ACCESS, acl, ap->a_cred, - ap->a_td); + if (type == ACL_TYPE_NFS4) + error = ufs_getacl_nfs4_internal(vp, acl, ap->a_td); + else + error = VOP_GETACL(vp, type, acl, ap->a_cred, ap->a_td); switch (error) { - case EOPNOTSUPP: - error = vaccess(vp->v_type, ip->i_mode, ip->i_uid, - ip->i_gid, ap->a_accmode, ap->a_cred, NULL); - break; case 0: - error = vaccess_acl_posix1e(vp->v_type, ip->i_uid, - ip->i_gid, acl, ap->a_accmode, ap->a_cred, NULL); + if (type == ACL_TYPE_NFS4) { + error = vaccess_acl_nfs4(vp->v_type, ip->i_uid, + ip->i_gid, acl, accmode, ap->a_cred, NULL); + } else { + error = vfs_unixify_accmode(&accmode); + if (error == 0) + error = vaccess_acl_posix1e(vp->v_type, ip->i_uid, + ip->i_gid, acl, accmode, ap->a_cred, NULL); + } break; default: - printf( -"ufs_access(): Error retrieving ACL on object (%d).\n", - error); + if (error != EOPNOTSUPP) + printf( +"ufs_accessx(): Error retrieving ACL on object (%d).\n", + error); /* * XXX: Fall back until debugged. Should * eventually possibly log an error, and return * EPERM for safety. */ - error = vaccess(vp->v_type, ip->i_mode, ip->i_uid, - ip->i_gid, ap->a_accmode, ap->a_cred, NULL); + error = vfs_unixify_accmode(&accmode); + if (error == 0) + error = vaccess(vp->v_type, ip->i_mode, ip->i_uid, + ip->i_gid, accmode, ap->a_cred, NULL); } acl_free(acl); - } else + + return (error); + } #endif /* !UFS_ACL */ + error = vfs_unixify_accmode(&accmode); + if (error == 0) error = vaccess(vp->v_type, ip->i_mode, ip->i_uid, ip->i_gid, - ap->a_accmode, ap->a_cred, NULL); + accmode, ap->a_cred, NULL); return (error); } @@ -608,11 +631,20 @@ ufs_setattr(ap) * check succeeds. */ if (vap->va_vaflags & VA_UTIMES_NULL) { - error = VOP_ACCESS(vp, VADMIN, cred, td); + /* + * NFSv4.1, draft 21, 6.2.1.3.1, Discussion of Mask Attributes + * + * "A user having ACL_WRITE_DATA or ACL_WRITE_ATTRIBUTES + * will be allowed to set the times [..] to the current + * server time." + * + * XXX: Calling it four times seems a little excessive. + */ + error = VOP_ACCESSX(vp, VWRITE_ATTRIBUTES, cred, td); if (error) error = VOP_ACCESS(vp, VWRITE, cred, td); } else - error = VOP_ACCESS(vp, VADMIN, cred, td); + error = VOP_ACCESSX(vp, VWRITE_ATTRIBUTES, cred, td); if (error) return (error); if (vap->va_atime.tv_sec != VNOVAL) @@ -652,6 +684,32 @@ ufs_setattr(ap) return (error); } +#ifdef UFS_ACL +static int +ufs_update_nfs4_acl_after_mode_change(struct vnode *vp, int mode, + int file_owner_id, struct ucred *cred, struct thread *td) +{ + int error; + struct acl *aclp; + + aclp = acl_alloc(M_WAITOK); + error = ufs_getacl_nfs4_internal(vp, aclp, td); + /* + * We don't have to handle EOPNOTSUPP here, as the filesystem claims + * it supports ACLs. + */ + if (error) + goto out; + + acl_nfs4_sync_acl_from_mode(aclp, mode, file_owner_id); + error = ufs_setacl_nfs4_internal(vp, aclp, td); + +out: + acl_free(aclp); + return (error); +} +#endif /* UFS_ACL */ + /* * Mark this file's access time for update for vfs_mark_atime(). This * is called from execve() and mmap(). @@ -689,7 +747,7 @@ ufs_chmod(vp, mode, cred, td) * To modify the permissions on a file, must possess VADMIN * for that file. */ - if ((error = VOP_ACCESS(vp, VADMIN, cred, td))) + if ((error = VOP_ACCESSX(vp, VWRITE_ACL, cred, td))) return (error); /* * Privileged processes may set the sticky bit on non-directories, @@ -706,11 +764,25 @@ ufs_chmod(vp, mode, cred, td) if (error) return (error); } + + /* + * Deny setting setuid if we are not the file owner. + */ + if ((mode & ISUID) && ip->i_uid != cred->cr_uid) { + error = priv_check_cred(cred, PRIV_VFS_ADMIN, 0); + if (error) + return (error); + } + ip->i_mode &= ~ALLPERMS; ip->i_mode |= (mode & ALLPERMS); DIP_SET(ip, i_mode, ip->i_mode); ip->i_flag |= IN_CHANGE; - return (0); +#ifdef UFS_ACL + if ((vp->v_mount->mnt_flag & MNT_NFS4ACLS) != 0) + error = ufs_update_nfs4_acl_after_mode_change(vp, mode, ip->i_uid, cred, td); +#endif + return (error); } /* @@ -742,14 +814,14 @@ ufs_chown(vp, uid, gid, cred, td) * To modify the ownership of a file, must possess VADMIN for that * file. */ - if ((error = VOP_ACCESS(vp, VADMIN, cred, td))) + if ((error = VOP_ACCESSX(vp, VWRITE_OWNER, cred, td))) return (error); /* * To change the owner of a file, or change the group of a file to a * group of which we are not a member, the caller must have * privilege. */ - if ((uid != ip->i_uid || + if (((uid != ip->i_uid && uid != cred->cr_uid) || (gid != ip->i_gid && !groupmember(gid, cred))) && (error = priv_check_cred(cred, PRIV_VFS_CHOWN, 0))) return (error); @@ -1397,6 +1469,190 @@ out: return (error); } +#ifdef UFS_ACL +static int +ufs_do_posix1e_acl_inheritance_dir(struct vnode *dvp, struct vnode *tvp, + mode_t dmode, struct ucred *cred, struct thread *td) +{ + int error; + struct inode *ip = VTOI(tvp); + struct acl *dacl, *acl; + + acl = acl_alloc(M_WAITOK); + dacl = acl_alloc(M_WAITOK); + + /* + * Retrieve default ACL from parent, if any. + */ + error = VOP_GETACL(dvp, ACL_TYPE_DEFAULT, acl, cred, td); + switch (error) { + case 0: + /* + * Retrieved a default ACL, so merge mode and ACL if + * necessary. If the ACL is empty, fall through to + * the "not defined or available" case. + */ + if (acl->acl_cnt != 0) { + dmode = acl_posix1e_newfilemode(dmode, acl); + ip->i_mode = dmode; + DIP_SET(ip, i_mode, dmode); + *dacl = *acl; + ufs_sync_acl_from_inode(ip, acl); + break; + } + /* FALLTHROUGH */ + + case EOPNOTSUPP: + /* + * Just use the mode as-is. + */ + ip->i_mode = dmode; + DIP_SET(ip, i_mode, dmode); + error = 0; + goto out; + + default: + goto out; + } + + /* + * XXX: If we abort now, will Soft Updates notify the extattr + * code that the EAs for the file need to be released? + */ + error = VOP_SETACL(tvp, ACL_TYPE_ACCESS, acl, cred, td); + if (error == 0) + error = VOP_SETACL(tvp, ACL_TYPE_DEFAULT, dacl, cred, td); + switch (error) { + case 0: + break; + + case EOPNOTSUPP: + /* + * XXX: This should not happen, as EOPNOTSUPP above + * was supposed to free acl. + */ + printf("ufs_mkdir: VOP_GETACL() but no VOP_SETACL()\n"); + /* + panic("ufs_mkdir: VOP_GETACL() but no VOP_SETACL()"); + */ + break; + + default: + goto out; + } + +out: + acl_free(acl); + acl_free(dacl); + + return (error); +} + +static int +ufs_do_posix1e_acl_inheritance_file(struct vnode *dvp, struct vnode *tvp, + mode_t mode, struct ucred *cred, struct thread *td) +{ + int error; + struct inode *ip = VTOI(tvp); + struct acl *acl; + + acl = acl_alloc(M_WAITOK); + + /* + * Retrieve default ACL for parent, if any. + */ + error = VOP_GETACL(dvp, ACL_TYPE_DEFAULT, acl, cred, td); + switch (error) { + case 0: + /* + * Retrieved a default ACL, so merge mode and ACL if + * necessary. + */ + if (acl->acl_cnt != 0) { + /* + * Two possible ways for default ACL to not + * be present. First, the EA can be + * undefined, or second, the default ACL can + * be blank. If it's blank, fall through to + * the it's not defined case. + */ + mode = acl_posix1e_newfilemode(mode, acl); + ip->i_mode = mode; + DIP_SET(ip, i_mode, mode); + ufs_sync_acl_from_inode(ip, acl); + break; + } + /* FALLTHROUGH */ + + case EOPNOTSUPP: + /* + * Just use the mode as-is. + */ + ip->i_mode = mode; + DIP_SET(ip, i_mode, mode); + error = 0; + goto out; + + default: + goto out; + } + + /* + * XXX: If we abort now, will Soft Updates notify the extattr + * code that the EAs for the file need to be released? + */ + error = VOP_SETACL(tvp, ACL_TYPE_ACCESS, acl, cred, td); + switch (error) { + case 0: + break; + + case EOPNOTSUPP: + /* + * XXX: This should not happen, as EOPNOTSUPP above was + * supposed to free acl. + */ + printf("ufs_makeinode: VOP_GETACL() but no " + "VOP_SETACL()\n"); + /* panic("ufs_makeinode: VOP_GETACL() but no " + "VOP_SETACL()"); */ + break; + + default: + goto out; + } + +out: + acl_free(acl); + + return (error); +} + +static int +ufs_do_nfs4_acl_inheritance(struct vnode *dvp, struct vnode *tvp, + mode_t child_mode, struct ucred *cred, struct thread *td) +{ + int error; + struct acl *parent_aclp, *child_aclp; + + parent_aclp = acl_alloc(M_WAITOK); + child_aclp = acl_alloc(M_WAITOK | M_ZERO); + + error = ufs_getacl_nfs4_internal(dvp, parent_aclp, td); + if (error) + goto out; + acl_nfs4_compute_inherited_acl(parent_aclp, child_aclp, + child_mode, VTOI(tvp)->i_uid, tvp->v_type == VDIR); + error = ufs_setacl_nfs4_internal(tvp, child_aclp, td); + if (error) + goto out; +out: + acl_free(parent_aclp); + acl_free(child_aclp); + + return (error); +} +#endif + /* * Mkdir system call */ @@ -1417,9 +1673,6 @@ ufs_mkdir(ap) struct buf *bp; struct dirtemplate dirtemplate, *dtp; struct direct newdir; -#ifdef UFS_ACL - struct acl *acl, *dacl; -#endif int error, dmode; long blkoff; @@ -1508,59 +1761,8 @@ ufs_mkdir(ap) #endif #endif /* !SUIDDIR */ ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; -#ifdef UFS_ACL - acl = dacl = NULL; - if ((dvp->v_mount->mnt_flag & MNT_ACLS) != 0) { - acl = acl_alloc(M_WAITOK); - dacl = acl_alloc(M_WAITOK); - - /* - * Retrieve default ACL from parent, if any. - */ - error = VOP_GETACL(dvp, ACL_TYPE_DEFAULT, acl, cnp->cn_cred, - cnp->cn_thread); - switch (error) { - case 0: - /* - * Retrieved a default ACL, so merge mode and ACL if - * necessary. If the ACL is empty, fall through to - * the "not defined or available" case. - */ - if (acl->acl_cnt != 0) { - dmode = acl_posix1e_newfilemode(dmode, acl); - ip->i_mode = dmode; - DIP_SET(ip, i_mode, dmode); - *dacl = *acl; - ufs_sync_acl_from_inode(ip, acl); - break; - } - /* FALLTHROUGH */ - - case EOPNOTSUPP: - /* - * Just use the mode as-is. - */ - ip->i_mode = dmode; - DIP_SET(ip, i_mode, dmode); - acl_free(acl); - acl_free(dacl); - dacl = acl = NULL; - break; - - default: - UFS_VFREE(tvp, ip->i_number, dmode); - vput(tvp); - acl_free(acl); - acl_free(dacl); - return (error); - } - } else { -#endif /* !UFS_ACL */ - ip->i_mode = dmode; - DIP_SET(ip, i_mode, dmode); -#ifdef UFS_ACL - } -#endif + ip->i_mode = dmode; + DIP_SET(ip, i_mode, dmode); tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */ ip->i_effnlink = 2; ip->i_nlink = 2; @@ -1595,40 +1797,16 @@ ufs_mkdir(ap) } #endif #ifdef UFS_ACL - if (acl != NULL) { - /* - * XXX: If we abort now, will Soft Updates notify the extattr - * code that the EAs for the file need to be released? - */ - error = VOP_SETACL(tvp, ACL_TYPE_ACCESS, acl, cnp->cn_cred, - cnp->cn_thread); - if (error == 0) - error = VOP_SETACL(tvp, ACL_TYPE_DEFAULT, dacl, - cnp->cn_cred, cnp->cn_thread); - switch (error) { - case 0: - break; - - case EOPNOTSUPP: - /* - * XXX: This should not happen, as EOPNOTSUPP above - * was supposed to free acl. - */ - printf("ufs_mkdir: VOP_GETACL() but no VOP_SETACL()\n"); - /* - panic("ufs_mkdir: VOP_GETACL() but no VOP_SETACL()"); - */ - break; - - default: - acl_free(acl); - acl_free(dacl); - dacl = acl = NULL; + if (dvp->v_mount->mnt_flag & MNT_ACLS) { + error = ufs_do_posix1e_acl_inheritance_dir(dvp, tvp, dmode, + cnp->cn_cred, cnp->cn_thread); + if (error) + goto bad; + } else if (dvp->v_mount->mnt_flag & MNT_NFS4ACLS) { + error = ufs_do_nfs4_acl_inheritance(dvp, tvp, dmode, + cnp->cn_cred, cnp->cn_thread); + if (error) goto bad; - } - acl_free(acl); - acl_free(dacl); - dacl = acl = NULL; } #endif /* !UFS_ACL */ @@ -1691,12 +1869,6 @@ bad: if (error == 0) { *ap->a_vpp = tvp; } else { -#ifdef UFS_ACL - if (acl != NULL) - acl_free(acl); - if (dacl != NULL) - acl_free(dacl); -#endif dp->i_effnlink--; dp->i_nlink--; DIP_SET(dp, i_nlink, dp->i_nlink); @@ -2117,6 +2289,7 @@ ufsfifo_pathconf(ap) switch (ap->a_name) { case _PC_ACL_EXTENDED: + case _PC_ACL_NFS4: case _PC_ACL_PATH_MAX: case _PC_MAC_PRESENT: return (ufs_pathconf(ap)); @@ -2169,9 +2342,21 @@ ufs_pathconf(ap) *ap->a_retval = 0; #endif break; + + case _PC_ACL_NFS4: +#ifdef UFS_ACL + if (ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) + *ap->a_retval = 1; + else + *ap->a_retval = 0; +#else + *ap->a_retval = 0; +#endif + break; + case _PC_ACL_PATH_MAX: #ifdef UFS_ACL - if (ap->a_vp->v_mount->mnt_flag & MNT_ACLS) + if (ap->a_vp->v_mount->mnt_flag & (MNT_ACLS | MNT_NFS4ACLS)) *ap->a_retval = ACL_MAX_ENTRIES; else *ap->a_retval = 3; @@ -2268,9 +2453,6 @@ ufs_makeinode(mode, dvp, vpp, cnp) struct inode *ip, *pdir; struct direct newdir; struct vnode *tvp; -#ifdef UFS_ACL - struct acl *acl; -#endif int error; pdir = VTOI(dvp); @@ -2350,62 +2532,8 @@ ufs_makeinode(mode, dvp, vpp, cnp) #endif #endif /* !SUIDDIR */ ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; -#ifdef UFS_ACL - acl = NULL; - if ((dvp->v_mount->mnt_flag & MNT_ACLS) != 0) { - acl = acl_alloc(M_WAITOK); - - /* - * Retrieve default ACL for parent, if any. - */ - error = VOP_GETACL(dvp, ACL_TYPE_DEFAULT, acl, cnp->cn_cred, - cnp->cn_thread); - switch (error) { - case 0: - /* - * Retrieved a default ACL, so merge mode and ACL if - * necessary. - */ - if (acl->acl_cnt != 0) { - /* - * Two possible ways for default ACL to not - * be present. First, the EA can be - * undefined, or second, the default ACL can - * be blank. If it's blank, fall through to - * the it's not defined case. - */ - mode = acl_posix1e_newfilemode(mode, acl); - ip->i_mode = mode; - DIP_SET(ip, i_mode, mode); - ufs_sync_acl_from_inode(ip, acl); - break; - } - /* FALLTHROUGH */ - - case EOPNOTSUPP: - /* - * Just use the mode as-is. - */ - ip->i_mode = mode; - DIP_SET(ip, i_mode, mode); - acl_free(acl); - acl = NULL; - break; - - default: - UFS_VFREE(tvp, ip->i_number, mode); - vput(tvp); - acl_free(acl); - acl = NULL; - return (error); - } - } else { -#endif - ip->i_mode = mode; - DIP_SET(ip, i_mode, mode); -#ifdef UFS_ACL - } -#endif + ip->i_mode = mode; + DIP_SET(ip, i_mode, mode); tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */ ip->i_effnlink = 1; ip->i_nlink = 1; @@ -2438,33 +2566,16 @@ ufs_makeinode(mode, dvp, vpp, cnp) } #endif #ifdef UFS_ACL - if (acl != NULL) { - /* - * XXX: If we abort now, will Soft Updates notify the extattr - * code that the EAs for the file need to be released? - */ - error = VOP_SETACL(tvp, ACL_TYPE_ACCESS, acl, cnp->cn_cred, - cnp->cn_thread); - switch (error) { - case 0: - break; - - case EOPNOTSUPP: - /* - * XXX: This should not happen, as EOPNOTSUPP above was - * supposed to free acl. - */ - printf("ufs_makeinode: VOP_GETACL() but no " - "VOP_SETACL()\n"); - /* panic("ufs_makeinode: VOP_GETACL() but no " - "VOP_SETACL()"); */ - break; - - default: - acl_free(acl); + if (dvp->v_mount->mnt_flag & MNT_ACLS) { + error = ufs_do_posix1e_acl_inheritance_file(dvp, tvp, mode, + cnp->cn_cred, cnp->cn_thread); + if (error) + goto bad; + } else if (dvp->v_mount->mnt_flag & MNT_NFS4ACLS) { + error = ufs_do_nfs4_acl_inheritance(dvp, tvp, mode, + cnp->cn_cred, cnp->cn_thread); + if (error) goto bad; - } - acl_free(acl); } #endif /* !UFS_ACL */ ufs_makedirentry(ip, cnp, &newdir); @@ -2496,7 +2607,7 @@ struct vop_vector ufs_vnodeops = { .vop_read = VOP_PANIC, .vop_reallocblks = VOP_PANIC, .vop_write = VOP_PANIC, - .vop_access = ufs_access, + .vop_accessx = ufs_accessx, .vop_bmap = ufs_bmap, .vop_cachedlookup = ufs_lookup, .vop_close = ufs_close, @@ -2540,7 +2651,7 @@ struct vop_vector ufs_vnodeops = { struct vop_vector ufs_fifoops = { .vop_default = &fifo_specops, .vop_fsync = VOP_PANIC, - .vop_access = ufs_access, + .vop_accessx = ufs_accessx, .vop_close = ufsfifo_close, .vop_getattr = ufs_getattr, .vop_inactive = ufs_inactive, |