Changeset View
Changeset View
Standalone View
Standalone View
head/sys/ufs/ufs/ufs_vnops.c
Show First 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | |||||
#include <sys/priv.h> | #include <sys/priv.h> | ||||
#include <sys/refcount.h> | #include <sys/refcount.h> | ||||
#include <sys/unistd.h> | #include <sys/unistd.h> | ||||
#include <sys/vnode.h> | #include <sys/vnode.h> | ||||
#include <sys/dirent.h> | #include <sys/dirent.h> | ||||
#include <sys/lockf.h> | #include <sys/lockf.h> | ||||
#include <sys/conf.h> | #include <sys/conf.h> | ||||
#include <sys/acl.h> | #include <sys/acl.h> | ||||
#include <sys/smr.h> | |||||
#include <security/mac/mac_framework.h> | #include <security/mac/mac_framework.h> | ||||
#include <sys/file.h> /* XXX */ | #include <sys/file.h> /* XXX */ | ||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
#include <vm/vm_extern.h> | #include <vm/vm_extern.h> | ||||
Show All 17 Lines | |||||
FEATURE(ufs_quota64, "64bit UFS disk quotas support"); | FEATURE(ufs_quota64, "64bit UFS disk quotas support"); | ||||
#endif | #endif | ||||
#ifdef SUIDDIR | #ifdef SUIDDIR | ||||
FEATURE(suiddir, | FEATURE(suiddir, | ||||
"Give all new files in directory the same ownership as the directory"); | "Give all new files in directory the same ownership as the directory"); | ||||
#endif | #endif | ||||
VFS_SMR_DECLARE; | |||||
#include <ufs/ffs/ffs_extern.h> | #include <ufs/ffs/ffs_extern.h> | ||||
static vop_accessx_t ufs_accessx; | static vop_accessx_t ufs_accessx; | ||||
static vop_fplookup_vexec_t ufs_fplookup_vexec; | |||||
static int ufs_chmod(struct vnode *, int, struct ucred *, struct thread *); | 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 int ufs_chown(struct vnode *, uid_t, gid_t, struct ucred *, struct thread *); | ||||
static vop_close_t ufs_close; | static vop_close_t ufs_close; | ||||
static vop_create_t ufs_create; | static vop_create_t ufs_create; | ||||
static vop_getattr_t ufs_getattr; | static vop_getattr_t ufs_getattr; | ||||
static vop_ioctl_t ufs_ioctl; | static vop_ioctl_t ufs_ioctl; | ||||
static vop_link_t ufs_link; | static vop_link_t ufs_link; | ||||
static int ufs_makeinode(int mode, struct vnode *, struct vnode **, struct componentname *, const char *); | static int ufs_makeinode(int mode, struct vnode *, struct vnode **, struct componentname *, const char *); | ||||
▲ Show 20 Lines • Show All 306 Lines • ▼ Show 20 Lines | |||||
#endif /* !UFS_ACL */ | #endif /* !UFS_ACL */ | ||||
error = vfs_unixify_accmode(&accmode); | error = vfs_unixify_accmode(&accmode); | ||||
if (error == 0) | if (error == 0) | ||||
error = vaccess(vp->v_type, ip->i_mode, ip->i_uid, ip->i_gid, | error = vaccess(vp->v_type, ip->i_mode, ip->i_uid, ip->i_gid, | ||||
accmode, ap->a_cred, NULL); | accmode, ap->a_cred, NULL); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | |||||
* VOP_FPLOOKUP_VEXEC routines are subject to special circumstances, see | |||||
* the comment above cache_fplookup for details. | |||||
*/ | |||||
static int | |||||
ufs_fplookup_vexec(ap) | |||||
struct vop_fplookup_vexec_args /* { | |||||
struct vnode *a_vp; | |||||
struct ucred *a_cred; | |||||
struct thread *a_td; | |||||
} */ *ap; | |||||
{ | |||||
struct vnode *vp; | |||||
struct inode *ip; | |||||
struct ucred *cred; | |||||
mode_t all_x, mode; | |||||
vp = ap->a_vp; | |||||
ip = VTOI_SMR(vp); | |||||
if (__predict_false(ip == NULL)) | |||||
return (EAGAIN); | |||||
/* | |||||
* XXX ACL race | |||||
* | |||||
* ACLs are not supported and UFS clears/sets this flag on mount and | |||||
* remount. However, we may still be racing with seeing them and there | |||||
* is no provision to make sure they were accounted for. This matches | |||||
* the behavior of the locked case, since the lookup there is also | |||||
* racy: mount takes no measures to block anyone from progressing. | |||||
*/ | |||||
all_x = S_IXUSR | S_IXGRP | S_IXOTH; | |||||
mode = atomic_load_short(&ip->i_mode); | |||||
if (__predict_true((mode & all_x) == all_x)) | |||||
return (0); | |||||
cred = ap->a_cred; | |||||
return (vaccess_vexec_smr(mode, ip->i_uid, ip->i_gid, cred)); | |||||
} | |||||
/* ARGSUSED */ | /* ARGSUSED */ | ||||
static int | static int | ||||
ufs_getattr(ap) | ufs_getattr(ap) | ||||
struct vop_getattr_args /* { | struct vop_getattr_args /* { | ||||
struct vnode *a_vp; | struct vnode *a_vp; | ||||
struct vattr *a_vap; | struct vattr *a_vap; | ||||
struct ucred *a_cred; | struct ucred *a_cred; | ||||
} */ *ap; | } */ *ap; | ||||
▲ Show 20 Lines • Show All 273 Lines • ▼ Show 20 Lines | |||||
static int | static int | ||||
ufs_chmod(vp, mode, cred, td) | ufs_chmod(vp, mode, cred, td) | ||||
struct vnode *vp; | struct vnode *vp; | ||||
int mode; | int mode; | ||||
struct ucred *cred; | struct ucred *cred; | ||||
struct thread *td; | struct thread *td; | ||||
{ | { | ||||
struct inode *ip = VTOI(vp); | struct inode *ip = VTOI(vp); | ||||
int error; | int newmode, error; | ||||
/* | /* | ||||
* To modify the permissions on a file, must possess VADMIN | * To modify the permissions on a file, must possess VADMIN | ||||
* for that file. | * for that file. | ||||
*/ | */ | ||||
if ((error = VOP_ACCESSX(vp, VWRITE_ACL, cred, td))) | if ((error = VOP_ACCESSX(vp, VWRITE_ACL, cred, td))) | ||||
return (error); | return (error); | ||||
/* | /* | ||||
Show All 16 Lines | ufs_chmod(vp, mode, cred, td) | ||||
* Deny setting setuid if we are not the file owner. | * Deny setting setuid if we are not the file owner. | ||||
*/ | */ | ||||
if ((mode & ISUID) && ip->i_uid != cred->cr_uid) { | if ((mode & ISUID) && ip->i_uid != cred->cr_uid) { | ||||
error = priv_check_cred(cred, PRIV_VFS_ADMIN); | error = priv_check_cred(cred, PRIV_VFS_ADMIN); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
} | } | ||||
ip->i_mode &= ~ALLPERMS; | newmode = ip->i_mode & ~ALLPERMS; | ||||
ip->i_mode |= (mode & ALLPERMS); | newmode |= (mode & ALLPERMS); | ||||
UFS_INODE_SET_MODE(ip, newmode); | |||||
DIP_SET(ip, i_mode, ip->i_mode); | DIP_SET(ip, i_mode, ip->i_mode); | ||||
UFS_INODE_SET_FLAG(ip, IN_CHANGE); | UFS_INODE_SET_FLAG(ip, IN_CHANGE); | ||||
#ifdef UFS_ACL | #ifdef UFS_ACL | ||||
if ((vp->v_mount->mnt_flag & MNT_NFS4ACLS) != 0) | if ((vp->v_mount->mnt_flag & MNT_NFS4ACLS) != 0) | ||||
error = ufs_update_nfs4_acl_after_mode_change(vp, mode, ip->i_uid, cred, td); | error = ufs_update_nfs4_acl_after_mode_change(vp, mode, ip->i_uid, cred, td); | ||||
#endif | #endif | ||||
if (error == 0 && (ip->i_flag & IN_CHANGE) != 0) | if (error == 0 && (ip->i_flag & IN_CHANGE) != 0) | ||||
error = UFS_UPDATE(vp, 0); | error = UFS_UPDATE(vp, 0); | ||||
▲ Show 20 Lines • Show All 107 Lines • ▼ Show 20 Lines | #ifdef QUOTA | ||||
return (error); | return (error); | ||||
good: | good: | ||||
if (getinoquota(ip)) | if (getinoquota(ip)) | ||||
panic("ufs_chown: lost quota"); | panic("ufs_chown: lost quota"); | ||||
#endif /* QUOTA */ | #endif /* QUOTA */ | ||||
UFS_INODE_SET_FLAG(ip, IN_CHANGE); | UFS_INODE_SET_FLAG(ip, IN_CHANGE); | ||||
if ((ip->i_mode & (ISUID | ISGID)) && (ouid != uid || ogid != gid)) { | if ((ip->i_mode & (ISUID | ISGID)) && (ouid != uid || ogid != gid)) { | ||||
if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID)) { | if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID)) { | ||||
ip->i_mode &= ~(ISUID | ISGID); | UFS_INODE_SET_MODE(ip, ip->i_mode & ~(ISUID | ISGID)); | ||||
DIP_SET(ip, i_mode, ip->i_mode); | DIP_SET(ip, i_mode, ip->i_mode); | ||||
} | } | ||||
} | } | ||||
error = UFS_UPDATE(vp, 0); | error = UFS_UPDATE(vp, 0); | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
▲ Show 20 Lines • Show All 225 Lines • ▼ Show 20 Lines | ufs_rename(ap) | ||||
struct thread *td = fcnp->cn_thread; | struct thread *td = fcnp->cn_thread; | ||||
struct inode *fip, *tip, *tdp, *fdp; | struct inode *fip, *tip, *tdp, *fdp; | ||||
struct direct newdir; | struct direct newdir; | ||||
off_t endoff; | off_t endoff; | ||||
int doingdirectory, newparent; | int doingdirectory, newparent; | ||||
int error = 0; | int error = 0; | ||||
struct mount *mp; | struct mount *mp; | ||||
ino_t ino; | ino_t ino; | ||||
bool want_seqc_end; | |||||
want_seqc_end = false; | |||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
if ((tcnp->cn_flags & HASBUF) == 0 || | if ((tcnp->cn_flags & HASBUF) == 0 || | ||||
(fcnp->cn_flags & HASBUF) == 0) | (fcnp->cn_flags & HASBUF) == 0) | ||||
panic("ufs_rename: no name"); | panic("ufs_rename: no name"); | ||||
#endif | #endif | ||||
endoff = 0; | endoff = 0; | ||||
mp = tdvp->v_mount; | mp = tdvp->v_mount; | ||||
VOP_UNLOCK(tdvp); | VOP_UNLOCK(tdvp); | ||||
▲ Show 20 Lines • Show All 187 Lines • ▼ Show 20 Lines | if (error) | ||||
goto unlockout; | goto unlockout; | ||||
if ((tcnp->cn_flags & SAVESTART) == 0) | if ((tcnp->cn_flags & SAVESTART) == 0) | ||||
panic("ufs_rename: lost to startdir"); | panic("ufs_rename: lost to startdir"); | ||||
} | } | ||||
if (fip->i_effnlink == 0 || fdp->i_effnlink == 0 || | if (fip->i_effnlink == 0 || fdp->i_effnlink == 0 || | ||||
tdp->i_effnlink == 0) | tdp->i_effnlink == 0) | ||||
panic("Bad effnlink fip %p, fdp %p, tdp %p", fip, fdp, tdp); | panic("Bad effnlink fip %p, fdp %p, tdp %p", fip, fdp, tdp); | ||||
if (tvp != NULL) | |||||
vn_seqc_write_begin(tvp); | |||||
vn_seqc_write_begin(tdvp); | |||||
vn_seqc_write_begin(fvp); | |||||
vn_seqc_write_begin(fdvp); | |||||
want_seqc_end = true; | |||||
/* | /* | ||||
* 1) Bump link count while we're moving stuff | * 1) Bump link count while we're moving stuff | ||||
* around. If we crash somewhere before | * around. If we crash somewhere before | ||||
* completing our work, the link count | * completing our work, the link count | ||||
* may be wrong, but correctable. | * may be wrong, but correctable. | ||||
*/ | */ | ||||
fip->i_effnlink++; | fip->i_effnlink++; | ||||
fip->i_nlink++; | fip->i_nlink++; | ||||
▲ Show 20 Lines • Show All 182 Lines • ▼ Show 20 Lines | relock: | ||||
* or open file descriptors. | * or open file descriptors. | ||||
*/ | */ | ||||
cache_purge(fvp); | cache_purge(fvp); | ||||
if (tvp) | if (tvp) | ||||
cache_purge(tvp); | cache_purge(tvp); | ||||
cache_purge_negative(tdvp); | cache_purge_negative(tdvp); | ||||
unlockout: | unlockout: | ||||
if (want_seqc_end) { | |||||
if (tvp != NULL) | |||||
vn_seqc_write_end(tvp); | |||||
vn_seqc_write_end(tdvp); | |||||
vn_seqc_write_end(fvp); | |||||
vn_seqc_write_end(fdvp); | |||||
} | |||||
vput(fdvp); | vput(fdvp); | ||||
vput(fvp); | vput(fvp); | ||||
if (tvp) | if (tvp) | ||||
vput(tvp); | vput(tvp); | ||||
/* | /* | ||||
* If compaction or fsync was requested do it now that other locks | * If compaction or fsync was requested do it now that other locks | ||||
* are no longer needed. | * are no longer needed. | ||||
*/ | */ | ||||
Show All 27 Lines | bad: | ||||
fip->i_nlink--; | fip->i_nlink--; | ||||
DIP_SET(fip, i_nlink, fip->i_nlink); | DIP_SET(fip, i_nlink, fip->i_nlink); | ||||
UFS_INODE_SET_FLAG(fip, IN_CHANGE); | UFS_INODE_SET_FLAG(fip, IN_CHANGE); | ||||
if (DOINGSOFTDEP(fvp)) | if (DOINGSOFTDEP(fvp)) | ||||
softdep_revert_link(tdp, fip); | softdep_revert_link(tdp, fip); | ||||
goto unlockout; | goto unlockout; | ||||
releout: | releout: | ||||
if (want_seqc_end) { | |||||
if (tvp != NULL) | |||||
vn_seqc_write_end(tvp); | |||||
vn_seqc_write_end(tdvp); | |||||
vn_seqc_write_end(fvp); | |||||
vn_seqc_write_end(fdvp); | |||||
} | |||||
vrele(fdvp); | vrele(fdvp); | ||||
vrele(fvp); | vrele(fvp); | ||||
vrele(tdvp); | vrele(tdvp); | ||||
if (tvp) | if (tvp) | ||||
vrele(tvp); | vrele(tvp); | ||||
return (error); | return (error); | ||||
} | } | ||||
Show All 18 Lines | ufs_do_posix1e_acl_inheritance_dir(struct vnode *dvp, struct vnode *tvp, | ||||
case 0: | case 0: | ||||
/* | /* | ||||
* Retrieved a default ACL, so merge mode and ACL if | * Retrieved a default ACL, so merge mode and ACL if | ||||
* necessary. If the ACL is empty, fall through to | * necessary. If the ACL is empty, fall through to | ||||
* the "not defined or available" case. | * the "not defined or available" case. | ||||
*/ | */ | ||||
if (acl->acl_cnt != 0) { | if (acl->acl_cnt != 0) { | ||||
dmode = acl_posix1e_newfilemode(dmode, acl); | dmode = acl_posix1e_newfilemode(dmode, acl); | ||||
ip->i_mode = dmode; | UFS_INODE_SET_MODE(ip, dmode); | ||||
DIP_SET(ip, i_mode, dmode); | DIP_SET(ip, i_mode, dmode); | ||||
*dacl = *acl; | *dacl = *acl; | ||||
ufs_sync_acl_from_inode(ip, acl); | ufs_sync_acl_from_inode(ip, acl); | ||||
break; | break; | ||||
} | } | ||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
case EOPNOTSUPP: | case EOPNOTSUPP: | ||||
/* | /* | ||||
* Just use the mode as-is. | * Just use the mode as-is. | ||||
*/ | */ | ||||
ip->i_mode = dmode; | UFS_INODE_SET_MODE(ip, dmode); | ||||
DIP_SET(ip, i_mode, dmode); | DIP_SET(ip, i_mode, dmode); | ||||
error = 0; | error = 0; | ||||
goto out; | goto out; | ||||
default: | default: | ||||
goto out; | goto out; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | if (acl->acl_cnt != 0) { | ||||
/* | /* | ||||
* Two possible ways for default ACL to not | * Two possible ways for default ACL to not | ||||
* be present. First, the EA can be | * be present. First, the EA can be | ||||
* undefined, or second, the default ACL can | * undefined, or second, the default ACL can | ||||
* be blank. If it's blank, fall through to | * be blank. If it's blank, fall through to | ||||
* the it's not defined case. | * the it's not defined case. | ||||
*/ | */ | ||||
mode = acl_posix1e_newfilemode(mode, acl); | mode = acl_posix1e_newfilemode(mode, acl); | ||||
ip->i_mode = mode; | UFS_INODE_SET_MODE(ip, mode); | ||||
DIP_SET(ip, i_mode, mode); | DIP_SET(ip, i_mode, mode); | ||||
ufs_sync_acl_from_inode(ip, acl); | ufs_sync_acl_from_inode(ip, acl); | ||||
break; | break; | ||||
} | } | ||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
case EOPNOTSUPP: | case EOPNOTSUPP: | ||||
/* | /* | ||||
* Just use the mode as-is. | * Just use the mode as-is. | ||||
*/ | */ | ||||
ip->i_mode = mode; | UFS_INODE_SET_MODE(ip, mode); | ||||
DIP_SET(ip, i_mode, mode); | DIP_SET(ip, i_mode, mode); | ||||
error = 0; | error = 0; | ||||
goto out; | goto out; | ||||
default: | default: | ||||
goto out; | goto out; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 95 Lines • ▼ Show 20 Lines | #endif | ||||
if (dp->i_effnlink < 2) { | if (dp->i_effnlink < 2) { | ||||
print_bad_link_count("ufs_mkdir", dvp); | print_bad_link_count("ufs_mkdir", dvp); | ||||
error = EINVAL; | error = EINVAL; | ||||
goto out; | goto out; | ||||
} | } | ||||
error = UFS_VALLOC(dvp, dmode, cnp->cn_cred, &tvp); | error = UFS_VALLOC(dvp, dmode, cnp->cn_cred, &tvp); | ||||
if (error) | if (error) | ||||
goto out; | goto out; | ||||
vn_seqc_write_begin(tvp); | |||||
ip = VTOI(tvp); | ip = VTOI(tvp); | ||||
ip->i_gid = dp->i_gid; | ip->i_gid = dp->i_gid; | ||||
DIP_SET(ip, i_gid, dp->i_gid); | DIP_SET(ip, i_gid, dp->i_gid); | ||||
#ifdef SUIDDIR | #ifdef SUIDDIR | ||||
{ | { | ||||
#ifdef QUOTA | #ifdef QUOTA | ||||
struct ucred ucred, *ucp; | struct ucred ucred, *ucp; | ||||
gid_t ucred_group; | gid_t ucred_group; | ||||
Show All 34 Lines | #endif | ||||
DIP_SET(ip, i_uid, ip->i_uid); | DIP_SET(ip, i_uid, ip->i_uid); | ||||
} | } | ||||
#ifdef QUOTA | #ifdef QUOTA | ||||
if ((error = getinoquota(ip)) || | if ((error = getinoquota(ip)) || | ||||
(error = chkiq(ip, 1, ucp, 0))) { | (error = chkiq(ip, 1, ucp, 0))) { | ||||
if (DOINGSOFTDEP(tvp)) | if (DOINGSOFTDEP(tvp)) | ||||
softdep_revert_link(dp, ip); | softdep_revert_link(dp, ip); | ||||
UFS_VFREE(tvp, ip->i_number, dmode); | UFS_VFREE(tvp, ip->i_number, dmode); | ||||
vn_seqc_write_end(tvp); | |||||
vgone(tvp); | vgone(tvp); | ||||
vput(tvp); | vput(tvp); | ||||
return (error); | return (error); | ||||
} | } | ||||
#endif | #endif | ||||
} | } | ||||
#else /* !SUIDDIR */ | #else /* !SUIDDIR */ | ||||
ip->i_uid = cnp->cn_cred->cr_uid; | ip->i_uid = cnp->cn_cred->cr_uid; | ||||
DIP_SET(ip, i_uid, ip->i_uid); | DIP_SET(ip, i_uid, ip->i_uid); | ||||
#ifdef QUOTA | #ifdef QUOTA | ||||
if ((error = getinoquota(ip)) || | if ((error = getinoquota(ip)) || | ||||
(error = chkiq(ip, 1, cnp->cn_cred, 0))) { | (error = chkiq(ip, 1, cnp->cn_cred, 0))) { | ||||
if (DOINGSOFTDEP(tvp)) | if (DOINGSOFTDEP(tvp)) | ||||
softdep_revert_link(dp, ip); | softdep_revert_link(dp, ip); | ||||
UFS_VFREE(tvp, ip->i_number, dmode); | UFS_VFREE(tvp, ip->i_number, dmode); | ||||
vn_seqc_write_end(tvp); | |||||
vgone(tvp); | vgone(tvp); | ||||
vput(tvp); | vput(tvp); | ||||
return (error); | return (error); | ||||
} | } | ||||
#endif | #endif | ||||
#endif /* !SUIDDIR */ | #endif /* !SUIDDIR */ | ||||
UFS_INODE_SET_FLAG(ip, IN_ACCESS | IN_CHANGE | IN_UPDATE); | UFS_INODE_SET_FLAG(ip, IN_ACCESS | IN_CHANGE | IN_UPDATE); | ||||
ip->i_mode = dmode; | UFS_INODE_SET_MODE(ip, dmode); | ||||
DIP_SET(ip, i_mode, dmode); | DIP_SET(ip, i_mode, dmode); | ||||
tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */ | tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */ | ||||
ip->i_effnlink = 2; | ip->i_effnlink = 2; | ||||
ip->i_nlink = 2; | ip->i_nlink = 2; | ||||
DIP_SET(ip, i_nlink, 2); | DIP_SET(ip, i_nlink, 2); | ||||
if (cnp->cn_flags & ISWHITEOUT) { | if (cnp->cn_flags & ISWHITEOUT) { | ||||
ip->i_flags |= UF_OPAQUE; | ip->i_flags |= UF_OPAQUE; | ||||
▲ Show 20 Lines • Show All 89 Lines • ▼ Show 20 Lines | #endif /* !UFS_ACL */ | ||||
else if (!DOINGSOFTDEP(dvp) && ((error = bwrite(bp)))) | else if (!DOINGSOFTDEP(dvp) && ((error = bwrite(bp)))) | ||||
goto bad; | goto bad; | ||||
ufs_makedirentry(ip, cnp, &newdir); | ufs_makedirentry(ip, cnp, &newdir); | ||||
error = ufs_direnter(dvp, tvp, &newdir, cnp, bp, 0); | error = ufs_direnter(dvp, tvp, &newdir, cnp, bp, 0); | ||||
bad: | bad: | ||||
if (error == 0) { | if (error == 0) { | ||||
*ap->a_vpp = tvp; | *ap->a_vpp = tvp; | ||||
vn_seqc_write_end(tvp); | |||||
} else { | } else { | ||||
dp->i_effnlink--; | dp->i_effnlink--; | ||||
dp->i_nlink--; | dp->i_nlink--; | ||||
DIP_SET(dp, i_nlink, dp->i_nlink); | DIP_SET(dp, i_nlink, dp->i_nlink); | ||||
UFS_INODE_SET_FLAG(dp, IN_CHANGE); | UFS_INODE_SET_FLAG(dp, IN_CHANGE); | ||||
/* | /* | ||||
* No need to do an explicit VOP_TRUNCATE here, vrele will | * No need to do an explicit VOP_TRUNCATE here, vrele will | ||||
* do this for us because we set the link count to 0. | * do this for us because we set the link count to 0. | ||||
*/ | */ | ||||
ip->i_effnlink = 0; | ip->i_effnlink = 0; | ||||
ip->i_nlink = 0; | ip->i_nlink = 0; | ||||
DIP_SET(ip, i_nlink, 0); | DIP_SET(ip, i_nlink, 0); | ||||
UFS_INODE_SET_FLAG(ip, IN_CHANGE); | UFS_INODE_SET_FLAG(ip, IN_CHANGE); | ||||
if (DOINGSOFTDEP(tvp)) | if (DOINGSOFTDEP(tvp)) | ||||
softdep_revert_mkdir(dp, ip); | softdep_revert_mkdir(dp, ip); | ||||
vn_seqc_write_end(tvp); | |||||
vgone(tvp); | vgone(tvp); | ||||
vput(tvp); | vput(tvp); | ||||
} | } | ||||
out: | out: | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 632 Lines • ▼ Show 20 Lines | if (DOINGSOFTDEP(tvp)) | ||||
softdep_revert_link(pdir, ip); | softdep_revert_link(pdir, ip); | ||||
UFS_VFREE(tvp, ip->i_number, mode); | UFS_VFREE(tvp, ip->i_number, mode); | ||||
vgone(tvp); | vgone(tvp); | ||||
vput(tvp); | vput(tvp); | ||||
return (error); | return (error); | ||||
} | } | ||||
#endif | #endif | ||||
#endif /* !SUIDDIR */ | #endif /* !SUIDDIR */ | ||||
vn_seqc_write_begin(tvp); /* Mostly to cover asserts */ | |||||
UFS_INODE_SET_FLAG(ip, IN_ACCESS | IN_CHANGE | IN_UPDATE); | UFS_INODE_SET_FLAG(ip, IN_ACCESS | IN_CHANGE | IN_UPDATE); | ||||
ip->i_mode = mode; | UFS_INODE_SET_MODE(ip, mode); | ||||
DIP_SET(ip, i_mode, mode); | DIP_SET(ip, i_mode, mode); | ||||
tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */ | tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */ | ||||
ip->i_effnlink = 1; | ip->i_effnlink = 1; | ||||
ip->i_nlink = 1; | ip->i_nlink = 1; | ||||
DIP_SET(ip, i_nlink, 1); | DIP_SET(ip, i_nlink, 1); | ||||
if (DOINGSOFTDEP(tvp)) | if (DOINGSOFTDEP(tvp)) | ||||
softdep_setup_create(VTOI(dvp), ip); | softdep_setup_create(VTOI(dvp), ip); | ||||
if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred) && | if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred) && | ||||
priv_check_cred(cnp->cn_cred, PRIV_VFS_SETGID)) { | priv_check_cred(cnp->cn_cred, PRIV_VFS_SETGID)) { | ||||
ip->i_mode &= ~ISGID; | UFS_INODE_SET_MODE(ip, ip->i_mode & ~ISGID); | ||||
DIP_SET(ip, i_mode, ip->i_mode); | DIP_SET(ip, i_mode, ip->i_mode); | ||||
} | } | ||||
if (cnp->cn_flags & ISWHITEOUT) { | if (cnp->cn_flags & ISWHITEOUT) { | ||||
ip->i_flags |= UF_OPAQUE; | ip->i_flags |= UF_OPAQUE; | ||||
DIP_SET(ip, i_flags, ip->i_flags); | DIP_SET(ip, i_flags, ip->i_flags); | ||||
} | } | ||||
Show All 23 Lines | if (dvp->v_mount->mnt_flag & MNT_ACLS) { | ||||
if (error) | if (error) | ||||
goto bad; | goto bad; | ||||
} | } | ||||
#endif /* !UFS_ACL */ | #endif /* !UFS_ACL */ | ||||
ufs_makedirentry(ip, cnp, &newdir); | ufs_makedirentry(ip, cnp, &newdir); | ||||
error = ufs_direnter(dvp, tvp, &newdir, cnp, NULL, 0); | error = ufs_direnter(dvp, tvp, &newdir, cnp, NULL, 0); | ||||
if (error) | if (error) | ||||
goto bad; | goto bad; | ||||
vn_seqc_write_end(tvp); | |||||
*vpp = tvp; | *vpp = tvp; | ||||
return (0); | return (0); | ||||
bad: | bad: | ||||
/* | /* | ||||
* Write error occurred trying to update the inode | * Write error occurred trying to update the inode | ||||
* or the directory so must deallocate the inode. | * or the directory so must deallocate the inode. | ||||
*/ | */ | ||||
ip->i_effnlink = 0; | ip->i_effnlink = 0; | ||||
ip->i_nlink = 0; | ip->i_nlink = 0; | ||||
DIP_SET(ip, i_nlink, 0); | DIP_SET(ip, i_nlink, 0); | ||||
UFS_INODE_SET_FLAG(ip, IN_CHANGE); | UFS_INODE_SET_FLAG(ip, IN_CHANGE); | ||||
if (DOINGSOFTDEP(tvp)) | if (DOINGSOFTDEP(tvp)) | ||||
softdep_revert_create(VTOI(dvp), ip); | softdep_revert_create(VTOI(dvp), ip); | ||||
vn_seqc_write_end(tvp); | |||||
vgone(tvp); | vgone(tvp); | ||||
vput(tvp); | vput(tvp); | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
ufs_ioctl(struct vop_ioctl_args *ap) | ufs_ioctl(struct vop_ioctl_args *ap) | ||||
{ | { | ||||
Show All 22 Lines | |||||
struct vop_vector ufs_vnodeops = { | struct vop_vector ufs_vnodeops = { | ||||
.vop_default = &default_vnodeops, | .vop_default = &default_vnodeops, | ||||
.vop_fsync = VOP_PANIC, | .vop_fsync = VOP_PANIC, | ||||
.vop_read = VOP_PANIC, | .vop_read = VOP_PANIC, | ||||
.vop_reallocblks = VOP_PANIC, | .vop_reallocblks = VOP_PANIC, | ||||
.vop_write = VOP_PANIC, | .vop_write = VOP_PANIC, | ||||
.vop_accessx = ufs_accessx, | .vop_accessx = ufs_accessx, | ||||
.vop_bmap = ufs_bmap, | .vop_bmap = ufs_bmap, | ||||
.vop_fplookup_vexec = ufs_fplookup_vexec, | |||||
.vop_cachedlookup = ufs_lookup, | .vop_cachedlookup = ufs_lookup, | ||||
.vop_close = ufs_close, | .vop_close = ufs_close, | ||||
.vop_create = ufs_create, | .vop_create = ufs_create, | ||||
.vop_getattr = ufs_getattr, | .vop_getattr = ufs_getattr, | ||||
.vop_inactive = ufs_inactive, | .vop_inactive = ufs_inactive, | ||||
.vop_ioctl = ufs_ioctl, | .vop_ioctl = ufs_ioctl, | ||||
.vop_link = ufs_link, | .vop_link = ufs_link, | ||||
.vop_lookup = vfs_cache_lookup, | .vop_lookup = vfs_cache_lookup, | ||||
▲ Show 20 Lines • Show All 63 Lines • Show Last 20 Lines |