/*
* 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/fsnotify.h>
#include <linux/jhash.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/kthread.h>
#include <linux/pagemap.h>
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/swap.h>
#include <linux/syscalls.h>
#include <linux/vmalloc.h>
#include "netfs.h"
/*
* Async machinery lives here.
* All commands being sent to server do _not_ require sync reply,
* instead, if it is really needed, like readdir or readpage, caller
* sleeps waiting for data, which will be placed into provided buffer
* and caller will be awakened.
*
* Every command response can come without some listener. For example
* readdir response will add new objects into cache without appropriate
* request from userspace. This is used in cache coherency.
*
* If object is not found for given data, it is discarded.
*
* All requests are received by dedicated kernel thread.
*/
/*
* Basic network sending/receiving functions.
* Blocked mode is used.
*/
static int netfs_data_recv(struct netfs_state *st, void *buf, u64 size)
{
struct msghdr msg;
struct kvec iov;
int err;
BUG_ON(!size);
iov.iov_base = buf;
iov.iov_len = size;
msg.msg_iov = (struct iovec *)&iov;
msg.msg_iovlen = 1;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = MSG_DONTWAIT;
err = kernel_recvmsg(st->socket, &msg, &iov, 1, iov.iov_len,
msg.msg_flags);
if (err <= 0) {
printk("%s: failed to recv data: size: %llu, err: %d.\n", __func__, size, err);
if (err == 0)
err = -ECONNRESET;
}
return err;
}
static int pohmelfs_data_recv(struct netfs_state *st, void *data, unsigned int size)
{
unsigned int revents = 0;
unsigned int err_mask = POLLERR | POLLHUP | POLLRDHUP;
unsigned int mask = err_mask | POLLIN;
int err = 0;
while (size && !err) {
revents = netfs_state_poll(st);
if (!(revents & mask)) {
DEFINE_WAIT(wait);
for (;;) {
prepare_to_wait(&st->thread_wait, &wait, TASK_INTERRUPTIBLE);
if (kthread_should_stop())
break;
revents = netfs_state_poll(st);
if (revents & mask)
break;
if (signal_pending(current))
break;
schedule();
continue;
}
finish_wait(&st->thread_wait, &wait);
}
err = 0;
netfs_state_lock(st);
if (st->socket && (st->read_socket == st->socket) && (revents & POLLIN)) {
err = netfs_data_recv(st<