Changeset View
Changeset View
Standalone View
Standalone View
sys/ufs/ffs/ffs_vnops.c
Show First 20 Lines • Show All 731 Lines • ▼ Show 20 Lines | ffs_write(ap) | ||||
struct inode *ip; | struct inode *ip; | ||||
struct fs *fs; | struct fs *fs; | ||||
struct buf *bp; | struct buf *bp; | ||||
ufs_lbn_t lbn; | ufs_lbn_t lbn; | ||||
off_t osize; | off_t osize; | ||||
ssize_t resid; | ssize_t resid; | ||||
int seqcount; | int seqcount; | ||||
int blkoffset, error, flags, ioflag, size, xfersize; | int blkoffset, error, flags, ioflag, size, xfersize; | ||||
bool want_seqc_end; | |||||
vp = ap->a_vp; | vp = ap->a_vp; | ||||
uio = ap->a_uio; | uio = ap->a_uio; | ||||
ioflag = ap->a_ioflag; | ioflag = ap->a_ioflag; | ||||
if (ap->a_ioflag & IO_EXT) | if (ap->a_ioflag & IO_EXT) | ||||
#ifdef notyet | #ifdef notyet | ||||
return (ffs_extwrite(vp, uio, ioflag, ap->a_cred)); | return (ffs_extwrite(vp, uio, ioflag, ap->a_cred)); | ||||
#else | #else | ||||
Show All 34 Lines | if ((uoff_t)uio->uio_offset + uio->uio_resid > fs->fs_maxfilesize) | ||||
return (EFBIG); | return (EFBIG); | ||||
/* | /* | ||||
* Maybe this should be above the vnode op call, but so long as | * Maybe this should be above the vnode op call, but so long as | ||||
* file servers have no limits, I don't think it matters. | * file servers have no limits, I don't think it matters. | ||||
*/ | */ | ||||
if (vn_rlimit_fsize(vp, uio, uio->uio_td)) | if (vn_rlimit_fsize(vp, uio, uio->uio_td)) | ||||
return (EFBIG); | return (EFBIG); | ||||
want_seqc_end = false; | |||||
if ((ip->i_mode & (ISUID | ISGID))) { | |||||
kib: I am not sure why clearing setuid/setgid bits on normal files (only normal files can be written… | |||||
Done Inline ActionsThis is not necessary. It alters i_mode and I think only modifying it within seqc is a good invariant to have. However, this can be pushed way down to wrap the actual modification, I have no strong opinion. mjg: This is not necessary. It alters i_mode and I think only modifying it within seqc is a good… | |||||
vn_seqc_write_begin(vp); | |||||
want_seqc_end = true; | |||||
} | |||||
resid = uio->uio_resid; | resid = uio->uio_resid; | ||||
osize = ip->i_size; | osize = ip->i_size; | ||||
if (seqcount > BA_SEQMAX) | if (seqcount > BA_SEQMAX) | ||||
flags = BA_SEQMAX << BA_SEQSHIFT; | flags = BA_SEQMAX << BA_SEQSHIFT; | ||||
else | else | ||||
flags = seqcount << BA_SEQSHIFT; | flags = seqcount << BA_SEQSHIFT; | ||||
if (ioflag & IO_SYNC) | if (ioflag & IO_SYNC) | ||||
flags |= IO_SYNC; | flags |= IO_SYNC; | ||||
▲ Show 20 Lines • Show All 102 Lines • ▼ Show 20 Lines | /* XXX is uio->uio_offset the right thing here? */ | ||||
/* | /* | ||||
* If we successfully wrote any data, and we are not the superuser | * If we successfully wrote any data, and we are not the superuser | ||||
* we clear the setuid and setgid bits as a precaution against | * we clear the setuid and setgid bits as a precaution against | ||||
* tampering. | * tampering. | ||||
*/ | */ | ||||
if ((ip->i_mode & (ISUID | ISGID)) && resid > uio->uio_resid && | if ((ip->i_mode & (ISUID | ISGID)) && resid > uio->uio_resid && | ||||
ap->a_cred) { | ap->a_cred) { | ||||
if (priv_check_cred(ap->a_cred, PRIV_VFS_RETAINSUGID)) { | if (priv_check_cred(ap->a_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); | ||||
} | } | ||||
} | } | ||||
if (error) { | if (error) { | ||||
if (ioflag & IO_UNIT) { | if (ioflag & IO_UNIT) { | ||||
(void)ffs_truncate(vp, osize, | (void)ffs_truncate(vp, osize, | ||||
IO_NORMAL | (ioflag & IO_SYNC), ap->a_cred); | IO_NORMAL | (ioflag & IO_SYNC), ap->a_cred); | ||||
uio->uio_offset -= resid - uio->uio_resid; | uio->uio_offset -= resid - uio->uio_resid; | ||||
uio->uio_resid = resid; | uio->uio_resid = resid; | ||||
} | } | ||||
} else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) { | } else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) { | ||||
error = ffs_update(vp, 1); | error = ffs_update(vp, 1); | ||||
if (ffs_fsfail_cleanup(VFSTOUFS(vp->v_mount), error)) | if (ffs_fsfail_cleanup(VFSTOUFS(vp->v_mount), error)) | ||||
error = ENXIO; | error = ENXIO; | ||||
} | } | ||||
if (want_seqc_end) | |||||
vn_seqc_write_end(vp); | |||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Extended attribute area reading. | * Extended attribute area reading. | ||||
*/ | */ | ||||
static int | static int | ||||
ffs_extread(struct vnode *vp, struct uio *uio, int ioflag) | ffs_extread(struct vnode *vp, struct uio *uio, int ioflag) | ||||
▲ Show 20 Lines • Show All 121 Lines • ▼ Show 20 Lines | ffs_extwrite(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *ucred) | ||||
struct inode *ip; | struct inode *ip; | ||||
struct ufs2_dinode *dp; | struct ufs2_dinode *dp; | ||||
struct fs *fs; | struct fs *fs; | ||||
struct buf *bp; | struct buf *bp; | ||||
ufs_lbn_t lbn; | ufs_lbn_t lbn; | ||||
off_t osize; | off_t osize; | ||||
ssize_t resid; | ssize_t resid; | ||||
int blkoffset, error, flags, size, xfersize; | int blkoffset, error, flags, size, xfersize; | ||||
bool want_seqc_end; | |||||
ip = VTOI(vp); | ip = VTOI(vp); | ||||
fs = ITOFS(ip); | fs = ITOFS(ip); | ||||
dp = ip->i_din2; | dp = ip->i_din2; | ||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
if (uio->uio_rw != UIO_WRITE || fs->fs_magic != FS_UFS2_MAGIC) | if (uio->uio_rw != UIO_WRITE || fs->fs_magic != FS_UFS2_MAGIC) | ||||
panic("ffs_extwrite: mode"); | panic("ffs_extwrite: mode"); | ||||
#endif | #endif | ||||
if (ioflag & IO_APPEND) | if (ioflag & IO_APPEND) | ||||
uio->uio_offset = dp->di_extsize; | uio->uio_offset = dp->di_extsize; | ||||
KASSERT(uio->uio_offset >= 0, ("ffs_extwrite: uio->uio_offset < 0")); | KASSERT(uio->uio_offset >= 0, ("ffs_extwrite: uio->uio_offset < 0")); | ||||
KASSERT(uio->uio_resid >= 0, ("ffs_extwrite: uio->uio_resid < 0")); | KASSERT(uio->uio_resid >= 0, ("ffs_extwrite: uio->uio_resid < 0")); | ||||
if ((uoff_t)uio->uio_offset + uio->uio_resid > | if ((uoff_t)uio->uio_offset + uio->uio_resid > | ||||
UFS_NXADDR * fs->fs_bsize) | UFS_NXADDR * fs->fs_bsize) | ||||
return (EFBIG); | return (EFBIG); | ||||
want_seqc_end = false; | |||||
if ((ip->i_mode & (ISUID | ISGID))) { | |||||
Not Done Inline ActionsSame. kib: Same. | |||||
vn_seqc_write_begin(vp); | |||||
want_seqc_end = true; | |||||
} | |||||
resid = uio->uio_resid; | resid = uio->uio_resid; | ||||
osize = dp->di_extsize; | osize = dp->di_extsize; | ||||
flags = IO_EXT; | flags = IO_EXT; | ||||
if (ioflag & IO_SYNC) | if (ioflag & IO_SYNC) | ||||
flags |= IO_SYNC; | flags |= IO_SYNC; | ||||
for (error = 0; uio->uio_resid > 0;) { | for (error = 0; uio->uio_resid > 0;) { | ||||
lbn = lblkno(fs, uio->uio_offset); | lbn = lblkno(fs, uio->uio_offset); | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | if (error || xfersize == 0) | ||||
break; | break; | ||||
UFS_INODE_SET_FLAG(ip, IN_CHANGE); | UFS_INODE_SET_FLAG(ip, IN_CHANGE); | ||||
} | } | ||||
/* | /* | ||||
* If we successfully wrote any data, and we are not the superuser | * If we successfully wrote any data, and we are not the superuser | ||||
* we clear the setuid and setgid bits as a precaution against | * we clear the setuid and setgid bits as a precaution against | ||||
* tampering. | * tampering. | ||||
*/ | */ | ||||
if ((ip->i_mode & (ISUID | ISGID)) && resid > uio->uio_resid && ucred) { | if ((ip->i_mode & (ISUID | ISGID))) { | ||||
if (priv_check_cred(ucred, PRIV_VFS_RETAINSUGID)) { | if (resid > uio->uio_resid && ucred && | ||||
ip->i_mode &= ~(ISUID | ISGID); | priv_check_cred(ucred, PRIV_VFS_RETAINSUGID)) { | ||||
UFS_INODE_SET_MODE(ip, ip->i_mode & ~(ISUID | ISGID)); | |||||
dp->di_mode = ip->i_mode; | dp->di_mode = ip->i_mode; | ||||
} | } | ||||
} | } | ||||
if (error) { | if (error) { | ||||
if (ioflag & IO_UNIT) { | if (ioflag & IO_UNIT) { | ||||
(void)ffs_truncate(vp, osize, | (void)ffs_truncate(vp, osize, | ||||
IO_EXT | (ioflag&IO_SYNC), ucred); | IO_EXT | (ioflag&IO_SYNC), ucred); | ||||
uio->uio_offset -= resid - uio->uio_resid; | uio->uio_offset -= resid - uio->uio_resid; | ||||
uio->uio_resid = resid; | uio->uio_resid = resid; | ||||
} | } | ||||
} else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) | } else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) | ||||
error = ffs_update(vp, 1); | error = ffs_update(vp, 1); | ||||
if (want_seqc_end) | |||||
vn_seqc_write_end(vp); | |||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Vnode operating to retrieve a named extended attribute. | * Vnode operating to retrieve a named extended attribute. | ||||
* | * | ||||
* Locate a particular EA (nspace:name) in the area (ptr:length), and return | * Locate a particular EA (nspace:name) in the area (ptr:length), and return | ||||
▲ Show 20 Lines • Show All 650 Lines • Show Last 20 Lines |
I am not sure why clearing setuid/setgid bits on normal files (only normal files can be written to) requires blocking of lockless lookup. The bits do not affect permissions to do the lookup.