mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-20 11:11:24 +00:00
Eliminate the layering violation in the kern_sendfile(). When quering
the file size, use VOP_GETATTR() instead of accessing vnode vm_object un_pager.vnp.vnp_size. Take the shared vnode lock earlier to cover the added VOP_GETATTR() call and, as consequence, the whole internal sendfile loop. Reduce vm object lock scope to not protect the local calculations. Note that this is the last misuse of the vnp_size in the tree, the others were removed from the ELF image activator by r230246. Reviewed by: alc Tested by: pho, bf (previous version) MFC after: 1 week
This commit is contained in:
parent
6ded84276d
commit
3d31767952
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=250027
@ -1902,8 +1902,10 @@ kern_sendfile(struct thread *td, struct sendfile_args *uap,
|
||||
struct mbuf *m = NULL;
|
||||
struct sf_buf *sf;
|
||||
struct vm_page *pg;
|
||||
struct vattr va;
|
||||
off_t off, xfsize, fsbytes = 0, sbytes = 0, rem = 0;
|
||||
int error, hdrlen = 0, mnw = 0;
|
||||
int bsize;
|
||||
struct sendfile_sync *sfs = NULL;
|
||||
|
||||
/*
|
||||
@ -2102,6 +2104,16 @@ kern_sendfile(struct thread *td, struct sendfile_args *uap,
|
||||
*/
|
||||
space -= hdrlen;
|
||||
|
||||
error = vn_lock(vp, LK_SHARED);
|
||||
if (error != 0)
|
||||
goto done;
|
||||
error = VOP_GETATTR(vp, &va, td->td_ucred);
|
||||
if (error != 0) {
|
||||
VOP_UNLOCK(vp, 0);
|
||||
goto done;
|
||||
}
|
||||
bsize = vp->v_mount->mnt_stat.f_iosize;
|
||||
|
||||
/*
|
||||
* Loop and construct maximum sized mbuf chain to be bulk
|
||||
* dumped into socket buffer.
|
||||
@ -2111,7 +2123,6 @@ kern_sendfile(struct thread *td, struct sendfile_args *uap,
|
||||
vm_offset_t pgoff;
|
||||
struct mbuf *m0;
|
||||
|
||||
VM_OBJECT_WLOCK(obj);
|
||||
/*
|
||||
* Calculate the amount to transfer.
|
||||
* Not to exceed a page, the EOF,
|
||||
@ -2121,12 +2132,11 @@ kern_sendfile(struct thread *td, struct sendfile_args *uap,
|
||||
if (uap->nbytes)
|
||||
rem = (uap->nbytes - fsbytes - loopbytes);
|
||||
else
|
||||
rem = obj->un_pager.vnp.vnp_size -
|
||||
rem = va.va_size -
|
||||
uap->offset - fsbytes - loopbytes;
|
||||
xfsize = omin(PAGE_SIZE - pgoff, rem);
|
||||
xfsize = omin(space - loopbytes, xfsize);
|
||||
if (xfsize <= 0) {
|
||||
VM_OBJECT_WUNLOCK(obj);
|
||||
done = 1; /* all data sent */
|
||||
break;
|
||||
}
|
||||
@ -2136,7 +2146,6 @@ kern_sendfile(struct thread *td, struct sendfile_args *uap,
|
||||
* Let the outer loop figure out how to handle it.
|
||||
*/
|
||||
if (space <= loopbytes) {
|
||||
VM_OBJECT_WUNLOCK(obj);
|
||||
done = 0;
|
||||
break;
|
||||
}
|
||||
@ -2146,6 +2155,7 @@ kern_sendfile(struct thread *td, struct sendfile_args *uap,
|
||||
* if not found or wait and loop if busy.
|
||||
*/
|
||||
pindex = OFF_TO_IDX(off);
|
||||
VM_OBJECT_WLOCK(obj);
|
||||
pg = vm_page_grab(obj, pindex, VM_ALLOC_NOBUSY |
|
||||
VM_ALLOC_NORMAL | VM_ALLOC_WIRED | VM_ALLOC_RETRY);
|
||||
|
||||
@ -2163,7 +2173,6 @@ kern_sendfile(struct thread *td, struct sendfile_args *uap,
|
||||
else if (uap->flags & SF_NODISKIO)
|
||||
error = EBUSY;
|
||||
else {
|
||||
int bsize;
|
||||
ssize_t resid;
|
||||
|
||||
/*
|
||||
@ -2175,13 +2184,6 @@ kern_sendfile(struct thread *td, struct sendfile_args *uap,
|
||||
|
||||
/*
|
||||
* Get the page from backing store.
|
||||
*/
|
||||
error = vn_lock(vp, LK_SHARED);
|
||||
if (error != 0)
|
||||
goto after_read;
|
||||
bsize = vp->v_mount->mnt_stat.f_iosize;
|
||||
|
||||
/*
|
||||
* XXXMAC: Because we don't have fp->f_cred
|
||||
* here, we pass in NOCRED. This is probably
|
||||
* wrong, but is consistent with our original
|
||||
@ -2191,8 +2193,6 @@ kern_sendfile(struct thread *td, struct sendfile_args *uap,
|
||||
trunc_page(off), UIO_NOCOPY, IO_NODELOCKED |
|
||||
IO_VMIO | ((MAXBSIZE / bsize) << IO_SEQSHIFT),
|
||||
td->td_ucred, NOCRED, &resid, td);
|
||||
VOP_UNLOCK(vp, 0);
|
||||
after_read:
|
||||
VM_OBJECT_WLOCK(obj);
|
||||
vm_page_io_finish(pg);
|
||||
if (!error)
|
||||
@ -2281,6 +2281,8 @@ kern_sendfile(struct thread *td, struct sendfile_args *uap,
|
||||
}
|
||||
}
|
||||
|
||||
VOP_UNLOCK(vp, 0);
|
||||
|
||||
/* Add the buffer chain to the socket buffer. */
|
||||
if (m != NULL) {
|
||||
int mlen, err;
|
||||
|
Loading…
Reference in New Issue
Block a user