static enum hrtimer_restart
MonitorTimerCB(struct hrtimer *timer)
{
    MvpkmVM *vm = container_of(timer, MvpkmVM, monTimer.timer);
    Mvpkm_WakeGuest(vm, ACTION_TIMER);
    return HRTIMER_NORESTART;
}
static int
MksckDgramSendMsg(struct kiocb *kiocb,
		  struct socket *sock,
		  struct msghdr *msg,
		  size_t len)
{
	int             err = 0;
	struct sock    *sk = sock->sk;
	Mksck          *peerMksck;
	Mksck_Datagram *dg;
	uint32          needed;
	uint32          write;
	Mksck_Address   fromAddr;

	if (msg->msg_flags & MSG_OOB)
		return -EOPNOTSUPP;

	if (len > MKSCK_XFER_MAX)
		return -EMSGSIZE;

	lock_sock(sk);
	do {
		Mksck *mksck;
		Mksck_Address peerAddr = {
		    .addr =
			(msg->msg_name ?
			 ((struct sockaddr_mk *)msg->msg_name)->mk_addr.addr :
			 MKSCK_ADDR_UNDEF)
		};

		err = MksckTryBind(sk);
		if (err)
			break;

		mksck = sk->sk_protinfo;
		fromAddr = mksck->addr;

		peerMksck = mksck->peer;
		if (peerMksck) {
			if (peerAddr.addr != MKSCK_ADDR_UNDEF &&
			    peerAddr.addr != mksck->peerAddr.addr) {
				err = -EISCONN;
				break;
			}

			ATOMIC_ADDV(peerMksck->refCount, 1);
		} else if (peerAddr.addr == MKSCK_ADDR_UNDEF) {
			err = -ENOTCONN;
		} else {
			err = LockPeer(peerAddr, &peerMksck);
		}
	} while (0);
	release_sock(sk);

	if (err)
		return err;

	needed = MKSCK_DGSIZE(len);
	while (1) {
		err = Mutex_Lock(&peerMksck->mutex, MutexModeEX);
		if (err < 0)
			goto decRefc;

		if (peerMksck->shutDown & MKSCK_SHUT_RD) {
			err = -ENOTCONN;
			goto unlockDecRefc;
		}

		write = Mksck_FindSendRoom(peerMksck, needed);
		if (write != MKSCK_FINDSENDROOM_FULL)
			break;

		if (msg->msg_flags & MSG_DONTWAIT) {
			err = -EAGAIN;
			goto unlockDecRefc;
		}

		peerMksck->foundFull++;
		err = Mutex_UnlSleep(&peerMksck->mutex, MutexModeEX,
				     MKSCK_CVAR_ROOM);
		if (err < 0) {
			PRINTK("MksckDgramSendMsg: aborted\n");
			goto decRefc;
		}
	}

	dg = (void *)&peerMksck->buff[write];

	dg->fromAddr = fromAddr;
	dg->len      = len;

	err = memcpy_fromiovec(dg->data, msg->msg_iov, len);
	if (err != 0)
		goto unlockDecRefc;

	Mksck_IncWriteIndex(peerMksck, write, needed);

	Mutex_UnlWake(&peerMksck->mutex, MutexModeEX, MKSCK_CVAR_FILL, false);

	if (peerMksck->rcvCBEntryMVA != 0) {
		MksckPage *peerMksckPage = Mksck_ToSharedPage(peerMksck);

		err = Mutex_Lock(&peerMksckPage->mutex, MutexModeSH);
		if (err == 0) {
			uint32 sockIdx = peerMksck->index;
			struct MvpkmVM *vm =
				(struct MvpkmVM *)peerMksckPage->vmHKVA;

			if (vm) {
				WorldSwitchPage *wsp = vm->wsp;

				ASSERT(sockIdx <
				       8 * sizeof(peerMksckPage->wakeVMMRecv));
				ATOMIC_ORV(peerMksckPage->wakeVMMRecv,
					   1U << sockIdx);

				if (wsp)
					Mvpkm_WakeGuest(vm, ACTION_MKSCK);
			}
			Mutex_Unlock(&peerMksckPage->mutex, MutexModeSH);
		}
	}

	if (!err)
		err = len;

decRefc:
	Mksck_DecRefc(peerMksck);
	return err;

unlockDecRefc:
	Mutex_Unlock(&peerMksck->mutex, MutexModeEX);
	goto decRefc;
}


static int
MksckFault(struct vm_area_struct *vma,
	   struct vm_fault *vmf)
{
	return VM_FAULT_SIGBUS;
}

static int
MksckMMap(struct file *file,
	  struct socket *sock,
	  struct vm_area_struct *vma)
{
	vma->vm_ops = &mksckVMOps;

	return 0;
}