FreeBSD/sys/fs/fuse/fuse_device.c
/*
 * fuse_device_read hangs on the queue of VFS messages.
 * When it's notified that there is a new one, it picks that and
 * passes up to the daemon
 */
fuse_device_read hangs on the queue of VFS messages.
When it's notified that there is a new one, it picks that and
passes up to the daemon
fuse_device_read hangs on the queue of VFS messages . When it ' s notified that there is a new one it picks that and passes up to the daemon
int
fuse_device_read(struct cdev *dev, struct uio *uio, int ioflag)
{
	int err;
	struct fuse_data *data;
	struct fuse_ticket *tick;
	void *buf[] = {NULL, NULL, NULL};
	int buflen[3];
	int i;
	FS_DEBUG("fuse device being read on thread %d\n", uio->uio_td->td_tid);
	err = devfs_get_cdevpriv((void **)&data);
	if (err != 0)
		return (err);
	fuse_lck_mtx_lock(data->ms_mtx);
again:
	if (fdata_get_dead(data)) {
		FS_DEBUG2G("we know early on that reader should be kicked so we don't wait for news\n");
		fuse_lck_mtx_unlock(data->ms_mtx);
		return (ENODEV);
	}
	if (!(tick = fuse_ms_pop(data))) {
		if (ioflag & O_NONBLOCK) {
			fuse_lck_mtx_unlock(data->ms_mtx);
			return (EAGAIN);
		} else {
			err = msleep(data, &data->ms_mtx, PCATCH, "fu_msg", 0);
			if (err != 0) {
				fuse_lck_mtx_unlock(data->ms_mtx);
				return (fdata_get_dead(data) ? ENODEV : err);
			}
			tick = fuse_ms_pop(data);
		}
	}
	if (!tick) {
		FS_DEBUG("no message on thread #%d\n", uio->uio_td->td_tid);
		goto again;
	}
	fuse_lck_mtx_unlock(data->ms_mtx);
	if (fdata_get_dead(data)) {
		FS_DEBUG2G("reader is to be sacked\n");
		if (tick) {
			FS_DEBUG2G("weird -- \"kick\" is set tho there is message\n");
			FUSE_ASSERT_MS_DONE(tick);
			fuse_ticket_drop(tick);
		}
		return (ENODEV);	
	}
	FS_DEBUG("message got on thread #%d\n", uio->uio_td->td_tid);
	KASSERT(tick->tk_ms_bufdata || tick->tk_ms_bufsize == 0,
	    ("non-null buf pointer with positive size"));
	switch (tick->tk_ms_type) {
	case FT_M_FIOV:
		buf[0] = tick->tk_ms_fiov.base;
		buflen[0] = tick->tk_ms_fiov.len;
		break;
	case FT_M_BUF:
		buf[0] = tick->tk_ms_fiov.base;
		buflen[0] = tick->tk_ms_fiov.len;
		buf[1] = tick->tk_ms_bufdata;
		buflen[1] = tick->tk_ms_bufsize;
		break;
	default:
		panic("unknown message type for fuse_ticket %p", tick);
	}
	for (i = 0; buf[i]; i++) {
		if (uio->uio_resid < buflen[i]) {
			fdata_set_dead(data);
			FS_DEBUG2G("daemon is stupid, kick it off...\n");
			err = ENODEV;
			break;
		}
		err = uiomove(buf[i], buflen[i], uio);
		if (err)
			break;
	}
	FUSE_ASSERT_MS_DONE(tick);
	fuse_ticket_drop(tick);
	return (err);
}
int fuse_device_read ( struct cdev * dev , struct uio * uio , int ioflag ) { int err ; struct fuse_data * data ; struct fuse_ticket * tick ; void * buf [ ] = { NULL , NULL , NULL } ; int buflen [ 3 ] ; int i ; FS_DEBUG ( " \n " , uio -> uio_td -> td_tid ) ; err = devfs_get_cdevpriv ( ( void * * ) & data ) ; if ( err != 0 ) return ( err ) ; fuse_lck_mtx_lock ( data -> ms_mtx ) ; again : if ( fdata_get_dead ( data ) ) { FS_DEBUG2G ( " \n " ) ; fuse_lck_mtx_unlock ( data -> ms_mtx ) ; return ( ENODEV ) ; } if ( ! ( tick = fuse_ms_pop ( data ) ) ) { if ( ioflag & O_NONBLOCK ) { fuse_lck_mtx_unlock ( data -> ms_mtx ) ; return ( EAGAIN ) ; } else { err = msleep ( data , & data -> ms_mtx , PCATCH , " " , 0 ) ; if ( err != 0 ) { fuse_lck_mtx_unlock ( data -> ms_mtx ) ; return ( fdata_get_dead ( data ) ? ENODEV : err ) ; } tick = fuse_ms_pop ( data ) ; } } if ( ! tick ) { FS_DEBUG ( " \n " , uio -> uio_td -> td_tid ) ; goto again ; } fuse_lck_mtx_unlock ( data -> ms_mtx ) ; if ( fdata_get_dead ( data ) ) { FS_DEBUG2G ( " \n " ) ; if ( tick ) { FS_DEBUG2G ( " \" \" \n " ) ; FUSE_ASSERT_MS_DONE ( tick ) ; fuse_ticket_drop ( tick ) ; } return ( ENODEV ) ; } FS_DEBUG ( " \n " , uio -> uio_td -> td_tid ) ; KASSERT ( tick -> tk_ms_bufdata || tick -> tk_ms_bufsize == 0 , ( " " ) ) ; switch ( tick -> tk_ms_type ) { case FT_M_FIOV : buf [ 0 ] = tick -> tk_ms_fiov . base ; buflen [ 0 ] = tick -> tk_ms_fiov . len ; break ; case FT_M_BUF : buf [ 0 ] = tick -> tk_ms_fiov . base ; buflen [ 0 ] = tick -> tk_ms_fiov . len ; buf [ 1 ] = tick -> tk_ms_bufdata ; buflen [ 1 ] = tick -> tk_ms_bufsize ; break ; default : panic ( " " , tick ) ; } for ( i = 0 ; buf [ i ] ; i ++ ) { if ( uio -> uio_resid < buflen [ i ] ) { fdata_set_dead ( data ) ; FS_DEBUG2G ( " \n " ) ; err = ENODEV ; break ; } err = uiomove ( buf [ i ] , buflen [ i ] , uio ) ; if ( err ) break ; } FUSE_ASSERT_MS_DONE ( tick ) ; fuse_ticket_drop ( tick ) ; return ( err ) ; }
fuse_device_read hangs on the queue of VFS messages.
fuse_device_read hangs on the queue of VFS messages .
/* check if we may block */ /* get outa here soon */ /*
		 * We can get here if fuse daemon suddenly terminates,
		 * eg, by being hit by a SIGKILL
		 * -- and some other cases, too, tho not totally clear, when
		 * (cv_signal/wakeup_one signals the whole process ?)
		 */ /*
		 * somebody somewhere -- eg., umount routine --
		 * wants this liaison finished off
		 */ /* This should make the daemon get off
					 * of us */ /*
		 * Why not ban mercilessly stupid daemons who can't keep up
		 * with us? (There is no much use of a partial read here...)
		 */ /*
		 * XXX note that in such cases Linux FUSE throws EIO at the
		 * syscall invoker and stands back to the message queue. The
		 * rationale should be made clear (and possibly adopt that
		 * behaviour). Keeping the current scheme at least makes
		 * fallacy as loud as possible...
		 */