FreeBSD/sys/kern/vfs_syscalls.c
/*
 * Unlike madvise(2), we do not make a best effort to remember every
 * possible caching hint.  Instead, we remember the last setting with
 * the exception that we will allow POSIX_FADV_NORMAL to adjust the
 * region of any current setting.
 */
Unlike madvise(2), we do not make a best effort to remember every
possible caching hint.  Instead, we remember the last setting with
the exception that we will allow POSIX_FADV_NORMAL to adjust the
region of any current setting.
Unlike madvise ( 2 ) we do not make a best effort to remember every possible caching hint . Instead we remember the last setting with the exception that we will allow POSIX_FADV_NORMAL to adjust the region of any current setting .
int
kern_posix_fadvise(struct thread *td, int fd, off_t offset, off_t len,
    int advice)
{
	struct fadvise_info *fa, *new;
	struct file *fp;
	struct vnode *vp;
	cap_rights_t rights;
	off_t end;
	int error;
	if (offset < 0 || len < 0 || offset > OFF_MAX - len)
		return (EINVAL);
	switch (advice) {
	case POSIX_FADV_SEQUENTIAL:
	case POSIX_FADV_RANDOM:
	case POSIX_FADV_NOREUSE:
		new = malloc(sizeof(*fa), M_FADVISE, M_WAITOK);
		break;
	case POSIX_FADV_NORMAL:
	case POSIX_FADV_WILLNEED:
	case POSIX_FADV_DONTNEED:
		new = NULL;
		break;
	default:
		return (EINVAL);
	}
	error = fget(td, fd, cap_rights_init(&rights), &fp);
	if (error != 0)
		goto out;
	if ((fp->f_ops->fo_flags & DFLAG_SEEKABLE) == 0) {
		error = ESPIPE;
		goto out;
	}
	if (fp->f_type != DTYPE_VNODE) {
		error = ENODEV;
		goto out;
	}
	vp = fp->f_vnode;
	if (vp->v_type != VREG) {
		error = ENODEV;
		goto out;
	}
	if (len == 0)
		end = OFF_MAX;
	else
		end = offset + len - 1;
	switch (advice) {
	case POSIX_FADV_SEQUENTIAL:
	case POSIX_FADV_RANDOM:
	case POSIX_FADV_NOREUSE:
		mtx_pool_lock(mtxpool_sleep, fp);
		fa = fp->f_advice;
		if (fa != NULL && fa->fa_advice == advice &&
		    ((fa->fa_start <= end && fa->fa_end >= offset) ||
		    (end != OFF_MAX && fa->fa_start == end + 1) ||
		    (fa->fa_end != OFF_MAX && fa->fa_end + 1 == offset))) {
			if (offset < fa->fa_start)
				fa->fa_start = offset;
			if (end > fa->fa_end)
				fa->fa_end = end;
		} else {
			new->fa_advice = advice;
			new->fa_start = offset;
			new->fa_end = end;
			fp->f_advice = new;
			new = fa;
		}
		mtx_pool_unlock(mtxpool_sleep, fp);
		break;
	case POSIX_FADV_NORMAL:
		mtx_pool_lock(mtxpool_sleep, fp);
		fa = fp->f_advice;
		if (fa != NULL) {
			if (offset <= fa->fa_start && end >= fa->fa_end) {
				new = fa;
				fp->f_advice = NULL;
			} else if (offset <= fa->fa_start &&
			    end >= fa->fa_start)
				fa->fa_start = end + 1;
			else if (offset <= fa->fa_end && end >= fa->fa_end)
				fa->fa_end = offset - 1;
			else if (offset >= fa->fa_start && end <= fa->fa_end) {
				new = fa;
				fp->f_advice = NULL;
			}
		}
		mtx_pool_unlock(mtxpool_sleep, fp);
		break;
	case POSIX_FADV_WILLNEED:
	case POSIX_FADV_DONTNEED:
		error = VOP_ADVISE(vp, offset, end, advice);
		break;
	}
out:
	if (fp != NULL)
		fdrop(fp, td);
	free(new, M_FADVISE);
	return (error);
}
int kern_posix_fadvise ( struct thread * td , int fd , off_t offset , off_t len , int advice ) { struct fadvise_info * fa , * new ; struct file * fp ; struct vnode * vp ; cap_rights_t rights ; off_t end ; int error ; if ( offset < 0 || len < 0 || offset > OFF_MAX - len ) return ( EINVAL ) ; switch ( advice ) { case POSIX_FADV_SEQUENTIAL : case POSIX_FADV_RANDOM : case POSIX_FADV_NOREUSE : new = malloc ( sizeof ( * fa ) , M_FADVISE , M_WAITOK ) ; break ; case POSIX_FADV_NORMAL : case POSIX_FADV_WILLNEED : case POSIX_FADV_DONTNEED : new = NULL ; break ; default : return ( EINVAL ) ; } error = fget ( td , fd , cap_rights_init ( & rights ) , & fp ) ; if ( error != 0 ) goto out ; if ( ( fp -> f_ops -> fo_flags & DFLAG_SEEKABLE ) == 0 ) { error = ESPIPE ; goto out ; } if ( fp -> f_type != DTYPE_VNODE ) { error = ENODEV ; goto out ; } vp = fp -> f_vnode ; if ( vp -> v_type != VREG ) { error = ENODEV ; goto out ; } if ( len == 0 ) end = OFF_MAX ; else end = offset + len - 1 ; switch ( advice ) { case POSIX_FADV_SEQUENTIAL : case POSIX_FADV_RANDOM : case POSIX_FADV_NOREUSE : mtx_pool_lock ( mtxpool_sleep , fp ) ; fa = fp -> f_advice ; if ( fa != NULL && fa -> fa_advice == advice && ( ( fa -> fa_start <= end && fa -> fa_end >= offset ) || ( end != OFF_MAX && fa -> fa_start == end + 1 ) || ( fa -> fa_end != OFF_MAX && fa -> fa_end + 1 == offset ) ) ) { if ( offset < fa -> fa_start ) fa -> fa_start = offset ; if ( end > fa -> fa_end ) fa -> fa_end = end ; } else { new -> fa_advice = advice ; new -> fa_start = offset ; new -> fa_end = end ; fp -> f_advice = new ; new = fa ; } mtx_pool_unlock ( mtxpool_sleep , fp ) ; break ; case POSIX_FADV_NORMAL : mtx_pool_lock ( mtxpool_sleep , fp ) ; fa = fp -> f_advice ; if ( fa != NULL ) { if ( offset <= fa -> fa_start && end >= fa -> fa_end ) { new = fa ; fp -> f_advice = NULL ; } else if ( offset <= fa -> fa_start && end >= fa -> fa_start ) fa -> fa_start = end + 1 ; else if ( offset <= fa -> fa_end && end >= fa -> fa_end ) fa -> fa_end = offset - 1 ; else if ( offset >= fa -> fa_start && end <= fa -> fa_end ) { new = fa ; fp -> f_advice = NULL ; } } mtx_pool_unlock ( mtxpool_sleep , fp ) ; break ; case POSIX_FADV_WILLNEED : case POSIX_FADV_DONTNEED : error = VOP_ADVISE ( vp , offset , end , advice ) ; break ; } out : if ( fp != NULL ) fdrop ( fp , td ) ; free ( new , M_FADVISE ) ; return ( error ) ; }
Unlike madvise(2), we do not make a best effort to remember every
 possible caching hint.
Unlike madvise ( 2 ) we do not make a best effort to remember every possible caching hint .
/* XXX: CAP_POSIX_FADVISE? */ /*
		 * Try to merge any existing non-standard region with
		 * this new region if possible, otherwise create a new
		 * non-standard region for this request.
		 */ /*
		 * If a the "normal" region overlaps with an existing
		 * non-standard region, trim or remove the
		 * non-standard region.
		 */ /*
				 * If the "normal" region is a middle
				 * portion of the existing
				 * non-standard region, just remove
				 * the whole thing rather than picking
				 * one side or the other to
				 * preserve.
				 */