Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F150530756
D36625.id110917.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
16 KB
Referenced Files
None
Subscribers
None
D36625.id110917.diff
View Options
diff --git a/sys/fs/ext2fs/ext2_vnops.c b/sys/fs/ext2fs/ext2_vnops.c
--- a/sys/fs/ext2fs/ext2_vnops.c
+++ b/sys/fs/ext2fs/ext2_vnops.c
@@ -2207,8 +2207,9 @@
* Maybe this should be above the vnode op call, but so long as
* file servers have no limits, I don't think it matters.
*/
- if (vn_rlimit_fsize(vp, uio, uio->uio_td))
- return (EFBIG);
+ error = vn_rlimit_fsize(vp, uio, uio->uio_td);
+ if (error != 0)
+ return (error);
resid = uio->uio_resid;
osize = ip->i_size;
diff --git a/sys/fs/fuse/fuse_io.c b/sys/fs/fuse/fuse_io.c
--- a/sys/fs/fuse/fuse_io.c
+++ b/sys/fs/fuse/fuse_io.c
@@ -338,8 +338,9 @@
if (ioflag & IO_APPEND)
uio_setoffset(uio, filesize);
- if (vn_rlimit_fsize(vp, uio, uio->uio_td))
- return (EFBIG);
+ err = vn_rlimit_fsize(vp, uio, uio->uio_td);
+ if (err != 0)
+ return (err);
fdisp_init(&fdi, 0);
@@ -493,8 +494,9 @@
if (ioflag & IO_APPEND)
uio_setoffset(uio, filesize);
- if (vn_rlimit_fsize(vp, uio, uio->uio_td))
- return (EFBIG);
+ err = vn_rlimit_fsize(vp, uio, uio->uio_td);
+ if (err != 0)
+ return (err);
do {
bool direct_append, extending;
diff --git a/sys/fs/msdosfs/msdosfs_vnops.c b/sys/fs/msdosfs/msdosfs_vnops.c
--- a/sys/fs/msdosfs/msdosfs_vnops.c
+++ b/sys/fs/msdosfs/msdosfs_vnops.c
@@ -456,6 +456,9 @@
*/
break;
}
+ error = vn_rlimit_trunc(vap->va_size, td);
+ if (error != 0)
+ return (error);
error = detrunc(dep, vap->va_size, 0, cred);
if (error)
return error;
@@ -611,7 +614,7 @@
{
int n;
int croffset;
- ssize_t resid;
+ ssize_t resid, r;
u_long osize;
int error = 0;
u_long count;
@@ -656,15 +659,15 @@
/*
* The caller is supposed to ensure that
* uio->uio_offset >= 0 and uio->uio_resid >= 0.
- */
- if ((uoff_t)uio->uio_offset + uio->uio_resid > MSDOSFS_FILESIZE_MAX)
- return (EFBIG);
-
- /*
+ *
* If they've exceeded their filesize limit, tell them about it.
*/
- if (vn_rlimit_fsize(vp, uio, uio->uio_td))
- return (EFBIG);
+ error = vn_rlimit_fsizex(vp, uio, MSDOSFS_FILESIZE_MAX, &r,
+ uio->uio_td);
+ if (error != 0) {
+ vn_rlimit_fsizex_res(uio, r);
+ return (error);
+ }
/*
* If the offset we are starting the write at is beyond the end of
@@ -674,8 +677,10 @@
*/
if (uio->uio_offset > dep->de_FileSize) {
error = deextend(dep, uio->uio_offset, cred);
- if (error)
+ if (error != 0) {
+ vn_rlimit_fsizex_res(uio, r);
return (error);
+ }
}
/*
@@ -818,6 +823,7 @@
}
} else if (ioflag & IO_SYNC)
error = deupdat(dep, 1);
+ vn_rlimit_fsizex_res(uio, r);
return (error);
}
diff --git a/sys/fs/nfsclient/nfs_clbio.c b/sys/fs/nfsclient/nfs_clbio.c
--- a/sys/fs/nfsclient/nfs_clbio.c
+++ b/sys/fs/nfsclient/nfs_clbio.c
@@ -1034,8 +1034,9 @@
* Maybe this should be above the vnode op call, but so long as
* file servers have no limits, i don't think it matters
*/
- if (vn_rlimit_fsize(vp, uio, td))
- return (EFBIG);
+ error = vn_rlimit_fsize(vp, uio, td);
+ if (error != 0)
+ return (error);
save2 = curthread_pflags2_set(TDP2_SBPAGES);
biosize = vp->v_bufobj.bo_bsize;
diff --git a/sys/fs/smbfs/smbfs_io.c b/sys/fs/smbfs/smbfs_io.c
--- a/sys/fs/smbfs/smbfs_io.c
+++ b/sys/fs/smbfs/smbfs_io.c
@@ -285,8 +285,9 @@
if (uiop->uio_resid == 0)
return 0;
- if (vn_rlimit_fsize(vp, uiop, td))
- return (EFBIG);
+ error = vn_rlimit_fsize(vp, uiop, td);
+ if (error != 0)
+ return (error);
scred = smbfs_malloc_scred();
smb_makescred(scred, td, cred);
diff --git a/sys/fs/tmpfs/tmpfs_subr.c b/sys/fs/tmpfs/tmpfs_subr.c
--- a/sys/fs/tmpfs/tmpfs_subr.c
+++ b/sys/fs/tmpfs/tmpfs_subr.c
@@ -120,7 +120,8 @@
*/
if (vp == NULL) {
KASSERT((object->flags & OBJ_TMPFS_VREF) == 0,
- ("object %p with OBJ_TMPFS_VREF but without vnode", object));
+ ("object %p with OBJ_TMPFS_VREF but without vnode",
+ object));
VM_OBJECT_WUNLOCK(object);
return;
}
@@ -131,7 +132,8 @@
VNPASS(vp->v_usecount > 0, vp);
} else {
VNASSERT((object->flags & OBJ_TMPFS_VREF) != 0, vp,
- ("object with writable mappings does not have a reference"));
+ ("object with writable mappings does not "
+ "have a reference"));
}
if (old == new) {
@@ -534,11 +536,13 @@
symlink = NULL;
if (!tmp->tm_nonc) {
- symlink = cache_symlink_alloc(nnode->tn_size + 1, M_WAITOK);
+ symlink = cache_symlink_alloc(nnode->tn_size + 1,
+ M_WAITOK);
symlink_smr = true;
}
if (symlink == NULL) {
- symlink = malloc(nnode->tn_size + 1, M_TMPFSNAME, M_WAITOK);
+ symlink = malloc(nnode->tn_size + 1, M_TMPFSNAME,
+ M_WAITOK);
symlink_smr = false;
}
memcpy(symlink, target, nnode->tn_size + 1);
@@ -550,14 +554,15 @@
* 1. nnode is not yet visible to the world
* 2. both tn_link_target and tn_link_smr get populated
* 3. release fence publishes their content
- * 4. tn_link_target content is immutable until node destruction,
- * where the pointer gets set to NULL
+ * 4. tn_link_target content is immutable until node
+ * destruction, where the pointer gets set to NULL
* 5. tn_link_smr is never changed once set
*
- * As a result it is sufficient to issue load consume on the node
- * pointer to also get the above content in a stable manner.
- * Worst case tn_link_smr flag may be set to true despite being stale,
- * while the target buffer is already cleared out.
+ * As a result it is sufficient to issue load consume
+ * on the node pointer to also get the above content
+ * in a stable manner. Worst case tn_link_smr flag
+ * may be set to true despite being stale, while the
+ * target buffer is already cleared out.
*/
atomic_store_ptr(&nnode->tn_link_target, symlink);
atomic_store_char((char *)&nnode->tn_link_smr, symlink_smr);
@@ -635,9 +640,10 @@
MPASS((node->tn_vpstate & TMPFS_VNODE_ALLOCATING) == 0);
/*
- * Make sure this is a node type we can deal with. Everything is explicitly
- * enumerated without the 'default' clause so the compiler can throw an
- * error in case a new type is added.
+ * Make sure this is a node type we can deal with. Everything
+ * is explicitly enumerated without the 'default' clause so
+ * the compiler can throw an error in case a new type is
+ * added.
*/
switch (node->tn_type) {
case VBLK:
@@ -651,17 +657,16 @@
case VNON:
case VBAD:
case VMARKER:
- panic("%s: bad type %d for node %p", __func__, (int)node->tn_type, node);
+ panic("%s: bad type %d for node %p", __func__,
+ (int)node->tn_type, node);
}
#endif
switch (node->tn_type) {
case VREG:
uobj = node->tn_reg.tn_aobj;
- if (uobj != NULL) {
- if (uobj->size != 0)
- atomic_subtract_long(&tmp->tm_pages_used, uobj->size);
- }
+ if (uobj != NULL && uobj->size != 0)
+ atomic_subtract_long(&tmp->tm_pages_used, uobj->size);
tmpfs_free_tmp(tmp);
@@ -1882,7 +1887,7 @@
*/
int
tmpfs_chflags(struct vnode *vp, u_long flags, struct ucred *cred,
- struct thread *p)
+ struct thread *td)
{
int error;
struct tmpfs_node *node;
@@ -1905,7 +1910,7 @@
* Callers may only modify the file flags on objects they
* have VADMIN rights for.
*/
- if ((error = VOP_ACCESS(vp, VADMIN, cred, p)))
+ if ((error = VOP_ACCESS(vp, VADMIN, cred, td)))
return (error);
/*
* Unprivileged processes are not permitted to unset system
@@ -1938,7 +1943,8 @@
* The vnode must be locked on entry and remain locked on exit.
*/
int
-tmpfs_chmod(struct vnode *vp, mode_t mode, struct ucred *cred, struct thread *p)
+tmpfs_chmod(struct vnode *vp, mode_t mode, struct ucred *cred,
+ struct thread *td)
{
int error;
struct tmpfs_node *node;
@@ -1961,7 +1967,7 @@
* To modify the permissions on a file, must possess VADMIN
* for that file.
*/
- if ((error = VOP_ACCESS(vp, VADMIN, cred, p)))
+ if ((error = VOP_ACCESS(vp, VADMIN, cred, td)))
return (error);
/*
@@ -1999,7 +2005,7 @@
*/
int
tmpfs_chown(struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred,
- struct thread *p)
+ struct thread *td)
{
int error;
struct tmpfs_node *node;
@@ -2032,7 +2038,7 @@
* To modify the ownership of a file, must possess VADMIN for that
* file.
*/
- if ((error = VOP_ACCESS(vp, VADMIN, cred, p)))
+ if ((error = VOP_ACCESS(vp, VADMIN, cred, td)))
return (error);
/*
@@ -2053,7 +2059,8 @@
node->tn_status |= TMPFS_NODE_CHANGED;
- if ((node->tn_mode & (S_ISUID | S_ISGID)) && (ouid != uid || ogid != gid)) {
+ if ((node->tn_mode & (S_ISUID | S_ISGID)) != 0 &&
+ (ouid != uid || ogid != gid)) {
if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID)) {
newmode = node->tn_mode & ~(S_ISUID | S_ISGID);
atomic_store_short(&node->tn_mode, newmode);
@@ -2072,7 +2079,7 @@
*/
int
tmpfs_chsize(struct vnode *vp, u_quad_t size, struct ucred *cred,
- struct thread *p)
+ struct thread *td)
{
int error;
struct tmpfs_node *node;
@@ -2113,6 +2120,10 @@
if (node->tn_flags & (IMMUTABLE | APPEND))
return (EPERM);
+ error = vn_rlimit_trunc(size, td);
+ if (error != 0)
+ return (error);
+
error = tmpfs_truncate(vp, size);
/*
* tmpfs_truncate will raise the NOTE_EXTEND and NOTE_ATTRIB kevents
@@ -2131,7 +2142,7 @@
*/
int
tmpfs_chtimes(struct vnode *vp, struct vattr *vap,
- struct ucred *cred, struct thread *l)
+ struct ucred *cred, struct thread *td)
{
int error;
struct tmpfs_node *node;
@@ -2148,21 +2159,17 @@
if (node->tn_flags & (IMMUTABLE | APPEND))
return (EPERM);
- error = vn_utimes_perm(vp, vap, cred, l);
+ error = vn_utimes_perm(vp, vap, cred, td);
if (error != 0)
return (error);
if (vap->va_atime.tv_sec != VNOVAL)
node->tn_accessed = true;
-
if (vap->va_mtime.tv_sec != VNOVAL)
node->tn_status |= TMPFS_NODE_MODIFIED;
-
if (vap->va_birthtime.tv_sec != VNOVAL)
node->tn_status |= TMPFS_NODE_MODIFIED;
-
tmpfs_itimes(vp, &vap->va_atime, &vap->va_mtime);
-
if (vap->va_birthtime.tv_sec != VNOVAL)
node->tn_birthtime = vap->va_birthtime;
ASSERT_VOP_ELOCKED(vp, "chtimes2");
diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c
--- a/sys/fs/tmpfs/tmpfs_vnops.c
+++ b/sys/fs/tmpfs/tmpfs_vnops.c
@@ -639,6 +639,7 @@
struct uio *uio;
struct tmpfs_node *node;
off_t oldsize;
+ ssize_t r;
int error, ioflag;
mode_t newmode;
@@ -655,11 +656,13 @@
return (0);
if (ioflag & IO_APPEND)
uio->uio_offset = node->tn_size;
- if (uio->uio_offset + uio->uio_resid >
- VFS_TO_TMPFS(vp->v_mount)->tm_maxfilesize)
- return (EFBIG);
- if (vn_rlimit_fsize(vp, uio, uio->uio_td))
- return (EFBIG);
+ error = vn_rlimit_fsizex(vp, uio, VFS_TO_TMPFS(vp->v_mount)->
+ tm_maxfilesize, &r, uio->uio_td);
+ if (error != 0) {
+ vn_rlimit_fsizex_res(uio, r);
+ return (error);
+ }
+
if (uio->uio_offset + uio->uio_resid > node->tn_size) {
error = tmpfs_reg_resize(vp, uio->uio_offset + uio->uio_resid,
FALSE);
@@ -685,6 +688,7 @@
MPASS(IMPLIES(error == 0, uio->uio_resid == 0));
MPASS(IMPLIES(error != 0, oldsize == node->tn_size));
+ vn_rlimit_fsizex_res(uio, r);
return (error);
}
diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -2372,42 +2372,124 @@
return (error);
}
+static void
+vn_send_sigxfsz(struct proc *p)
+{
+ PROC_LOCK(p);
+ kern_psignal(p, SIGXFSZ);
+ PROC_UNLOCK(p);
+}
+
int
-vn_rlimit_fsize(const struct vnode *vp, const struct uio *uio,
- struct thread *td)
+vn_rlimit_trunc(u_quad_t size, struct thread *td)
+{
+ if (size <= lim_cur(td, RLIMIT_FSIZE))
+ return (0);
+ vn_send_sigxfsz(td->td_proc);
+ return (EFBIG);
+}
+
+static int
+vn_rlimit_fsizex1(const struct vnode *vp, struct uio *uio, off_t maxfsz,
+ bool adj, struct thread *td)
{
off_t lim;
bool ktr_write;
- if (td == NULL)
+ if (vp->v_type != VREG)
return (0);
/*
- * There are conditions where the limit is to be ignored.
- * However, since it is almost never reached, check it first.
+ * Handle file system maximum file size.
+ */
+ if (maxfsz != 0 && uio->uio_offset + uio->uio_resid > maxfsz) {
+ if (!adj || uio->uio_offset >= maxfsz)
+ return (EFBIG);
+ uio->uio_resid = maxfsz - uio->uio_offset;
+ }
+
+ /*
+ * This is kernel write (e.g. vnode_pager) or accounting
+ * write, ignore limit.
+ */
+ if (td == NULL || (td->td_pflags2 & TDP2_ACCT) != 0)
+ return (0);
+
+ /*
+ * Calculate file size limit.
*/
ktr_write = (td->td_pflags & TDP_INKTRACE) != 0;
- lim = lim_cur(td, RLIMIT_FSIZE);
- if (__predict_false(ktr_write))
- lim = td->td_ktr_io_lim;
+ lim = __predict_false(ktr_write) ? td->td_ktr_io_lim :
+ lim_cur(td, RLIMIT_FSIZE);
+
+ /*
+ * Is the limit reached?
+ */
if (__predict_true((uoff_t)uio->uio_offset + uio->uio_resid <= lim))
return (0);
/*
- * The limit is reached.
+ * Prepared filesystems can handle writes truncated to the
+ * file size limit.
*/
- if (vp->v_type != VREG ||
- (td->td_pflags2 & TDP2_ACCT) != 0)
+ if (adj && (uoff_t)uio->uio_offset < lim) {
+ uio->uio_resid = lim - (uoff_t)uio->uio_offset;
return (0);
-
- if (!ktr_write || ktr_filesize_limit_signal) {
- PROC_LOCK(td->td_proc);
- kern_psignal(td->td_proc, SIGXFSZ);
- PROC_UNLOCK(td->td_proc);
}
+
+ if (!ktr_write || ktr_filesize_limit_signal)
+ vn_send_sigxfsz(td->td_proc);
return (EFBIG);
}
+/*
+ * Helper for VOP_WRITE() implementations, the common code to
+ * handle maximum supported file size on the filesystem, and
+ * RLIMIT_FSIZE, except for special writes from accounting subsystem
+ * and ktrace.
+ *
+ * For maximum file size (maxfsz argument):
+ * - return EFBIG if uio_offset is beyond it
+ * - otherwise, clamp uio_resid if write would extend file beyond maxfsz.
+ *
+ * For RLIMIT_FSIZE:
+ * - return EFBIG and send SIGXFSZ if uio_offset is beyond the limit
+ * - otherwise, clamp uio_resid if write would extend file beyond limit.
+ *
+ * If clamping occured, the adjustment for uio_resid is stored in
+ * *resid_adj, to be re-applied by vn_rlimit_fsizex_res() on return
+ * from the VOP.
+ */
+int
+vn_rlimit_fsizex(const struct vnode *vp, struct uio *uio, off_t maxfsz,
+ ssize_t *resid_adj, struct thread *td)
+{
+ ssize_t resid_orig;
+ int error;
+ bool adj;
+
+ resid_orig = uio->uio_resid;
+ adj = resid_adj != NULL;
+ error = vn_rlimit_fsizex1(vp, uio, maxfsz, adj, td);
+ if (adj)
+ *resid_adj = resid_orig - uio->uio_resid;
+ return (error);
+}
+
+void
+vn_rlimit_fsizex_res(struct uio *uio, ssize_t resid_adj)
+{
+ uio->uio_resid += resid_adj;
+}
+
+int
+vn_rlimit_fsize(const struct vnode *vp, const struct uio *uio,
+ struct thread *td)
+{
+ return (vn_rlimit_fsizex(vp, __DECONST(struct uio *, uio), 0, NULL,
+ td));
+}
+
int
vn_chmod(struct file *fp, mode_t mode, struct ucred *active_cred,
struct thread *td)
@@ -3220,8 +3302,6 @@
io.uio_offset = *outoffp;
io.uio_resid = len;
error = vn_rlimit_fsize(outvp, &io, fsize_td);
- if (error != 0)
- error = EFBIG;
}
if (VOP_PATHCONF(outvp, _PC_MIN_HOLE_SIZE, &holeout) != 0)
holeout = 0;
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -786,6 +786,10 @@
int vn_read_from_obj(struct vnode *vp, struct uio *uio);
int vn_rlimit_fsize(const struct vnode *vp, const struct uio *uio,
struct thread *td);
+int vn_rlimit_fsizex(const struct vnode *vp, struct uio *uio,
+ off_t maxfsz, ssize_t *resid_adj, struct thread *td);
+void vn_rlimit_fsizex_res(struct uio *uio, ssize_t resid_adj);
+int vn_rlimit_trunc(u_quad_t size, struct thread *td);
int vn_start_write(struct vnode *vp, struct mount **mpp, int flags);
int vn_start_secondary_write(struct vnode *vp, struct mount **mpp,
int flags);
diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c
--- a/sys/ufs/ffs/ffs_vnops.c
+++ b/sys/ufs/ffs/ffs_vnops.c
@@ -839,7 +839,7 @@
struct buf *bp;
ufs_lbn_t lbn;
off_t osize;
- ssize_t resid;
+ ssize_t resid, r;
int seqcount;
int blkoffset, error, flags, ioflag, size, xfersize;
@@ -888,14 +888,17 @@
KASSERT(uio->uio_resid >= 0, ("ffs_write: uio->uio_resid < 0"));
KASSERT(uio->uio_offset >= 0, ("ffs_write: uio->uio_offset < 0"));
fs = ITOFS(ip);
- if ((uoff_t)uio->uio_offset + uio->uio_resid > fs->fs_maxfilesize)
- return (EFBIG);
+
/*
* Maybe this should be above the vnode op call, but so long as
* file servers have no limits, I don't think it matters.
*/
- if (vn_rlimit_fsize(vp, uio, uio->uio_td))
- return (EFBIG);
+ error = vn_rlimit_fsizex(vp, uio, fs->fs_maxfilesize, &r,
+ uio->uio_td);
+ if (error != 0) {
+ vn_rlimit_fsizex_res(uio, r);
+ return (error);
+ }
resid = uio->uio_resid;
osize = ip->i_size;
@@ -1036,6 +1039,7 @@
if (ffs_fsfail_cleanup(VFSTOUFS(vp->v_mount), error))
error = ENXIO;
}
+ vn_rlimit_fsizex_res(uio, r);
return (error);
}
diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c
--- a/sys/ufs/ufs/ufs_vnops.c
+++ b/sys/ufs/ufs/ufs_vnops.c
@@ -755,6 +755,9 @@
*/
return (0);
}
+ error = vn_rlimit_trunc(vap->va_size, td);
+ if (error != 0)
+ return (error);
if ((error = UFS_TRUNCATE(vp, vap->va_size, IO_NORMAL |
((vap->va_vaflags & VA_SYNC) != 0 ? IO_SYNC : 0),
cred)) != 0)
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Apr 3, 2:19 AM (19 h, 22 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
30741324
Default Alt Text
D36625.id110917.diff (16 KB)
Attached To
Mode
D36625: Improve POSIX compliance for RLIMIT_FSIZE
Attached
Detach File
Event Timeline
Log In to Comment