| 561 | } |
| 562 | |
| 563 | static int |
| 564 | sendfile_getobj(struct thread *td, struct file *fp, vm_object_t *obj_res, |
| 565 | struct vnode **vp_res, struct shmfd **shmfd_res, off_t *obj_size, |
| 566 | int *bsize) |
| 567 | { |
| 568 | struct vattr va; |
| 569 | vm_object_t obj; |
| 570 | struct vnode *vp; |
| 571 | struct shmfd *shmfd; |
| 572 | int error; |
| 573 | |
| 574 | vp = *vp_res = NULL; |
| 575 | obj = NULL; |
| 576 | shmfd = *shmfd_res = NULL; |
| 577 | *bsize = 0; |
| 578 | |
| 579 | /* |
| 580 | * The file descriptor must be a regular file and have a |
| 581 | * backing VM object. |
| 582 | */ |
| 583 | if (fp->f_type == DTYPE_VNODE) { |
| 584 | vp = fp->f_vnode; |
| 585 | vn_lock(vp, LK_SHARED | LK_RETRY); |
| 586 | if (vp->v_type != VREG) { |
| 587 | error = EINVAL; |
| 588 | goto out; |
| 589 | } |
| 590 | *bsize = vp->v_mount->mnt_stat.f_iosize; |
| 591 | obj = vp->v_object; |
| 592 | if (obj == NULL) { |
| 593 | error = EINVAL; |
| 594 | goto out; |
| 595 | } |
| 596 | |
| 597 | /* |
| 598 | * Use the pager size when available to simplify synchronization |
| 599 | * with filesystems, which otherwise must atomically update both |
| 600 | * the vnode pager size and file size. |
| 601 | */ |
| 602 | if (obj->type == OBJT_VNODE) { |
| 603 | VM_OBJECT_RLOCK(obj); |
| 604 | *obj_size = obj->un_pager.vnp.vnp_size; |
| 605 | } else { |
| 606 | error = VOP_GETATTR(vp, &va, td->td_ucred); |
| 607 | if (error != 0) |
| 608 | goto out; |
| 609 | *obj_size = va.va_size; |
| 610 | VM_OBJECT_RLOCK(obj); |
| 611 | } |
| 612 | } else if (fp->f_type == DTYPE_SHM) { |
| 613 | error = 0; |
| 614 | shmfd = fp->f_data; |
| 615 | obj = shmfd->shm_object; |
| 616 | VM_OBJECT_RLOCK(obj); |
| 617 | *obj_size = shmfd->shm_size; |
| 618 | } else { |
| 619 | error = EINVAL; |
| 620 | goto out; |
no test coverage detected