diff options
Diffstat (limited to 'net/9p')
| -rw-r--r-- | net/9p/client.c | 30 | ||||
| -rw-r--r-- | net/9p/trans_fd.c | 116 | ||||
| -rw-r--r-- | net/9p/trans_rdma.c | 26 | ||||
| -rw-r--r-- | net/9p/trans_virtio.c | 19 | 
4 files changed, 105 insertions, 86 deletions
diff --git a/net/9p/client.c b/net/9p/client.c index ee8fd6bd403..0004cbaac4a 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -204,7 +204,7 @@ free_and_return:  	return ret;  } -struct p9_fcall *p9_fcall_alloc(int alloc_msize) +static struct p9_fcall *p9_fcall_alloc(int alloc_msize)  {  	struct p9_fcall *fc;  	fc = kmalloc(sizeof(struct p9_fcall) + alloc_msize, GFP_NOFS); @@ -415,9 +415,17 @@ static void p9_free_req(struct p9_client *c, struct p9_req_t *r)   * req: request received   *   */ -void p9_client_cb(struct p9_client *c, struct p9_req_t *req) +void p9_client_cb(struct p9_client *c, struct p9_req_t *req, int status)  {  	p9_debug(P9_DEBUG_MUX, " tag %d\n", req->tc->tag); + +	/* +	 * This barrier is needed to make sure any change made to req before +	 * the other thread wakes up will indeed be seen by the waiting side. +	 */ +	smp_wmb(); +	req->status = status; +  	wake_up(req->wq);  	p9_debug(P9_DEBUG_MUX, "wakeup: %d\n", req->tc->tag);  } @@ -655,16 +663,13 @@ static int p9_client_flush(struct p9_client *c, struct p9_req_t *oldreq)  	if (IS_ERR(req))  		return PTR_ERR(req); -  	/*  	 * if we haven't received a response for oldreq,  	 * remove it from the list  	 */ -	if (oldreq->status == REQ_STATUS_FLSH) { -		spin_lock(&c->lock); -		list_del(&oldreq->req_list); -		spin_unlock(&c->lock); -	} +	if (oldreq->status == REQ_STATUS_SENT) +		if (c->trans_mod->cancelled) +			c->trans_mod->cancelled(c, oldreq);  	p9_free_req(c, req);  	return 0; @@ -751,6 +756,12 @@ again:  	err = wait_event_interruptible(*req->wq,  				       req->status >= REQ_STATUS_RCVD); +	/* +	 * Make sure our req is coherent with regard to updates in other +	 * threads - echoes to wmb() in the callback +	 */ +	smp_rmb(); +  	if ((err == -ERESTARTSYS) && (c->status == Connected)  				  && (type == P9_TFLUSH)) {  		sigpending = 1; @@ -1012,9 +1023,6 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)  		goto destroy_tagpool;  	if (!clnt->trans_mod) -		clnt->trans_mod = v9fs_get_trans_by_name("virtio"); - -	if (!clnt->trans_mod)  		clnt->trans_mod = v9fs_get_default_trans();  	if (clnt->trans_mod == NULL) { diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index 3ffda1b3799..80d08f6664c 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -66,20 +66,6 @@ struct p9_fd_opts {  	int privport;  }; -/** - * struct p9_trans_fd - transport state - * @rd: reference to file to read from - * @wr: reference of file to write to - * @conn: connection state reference - * - */ - -struct p9_trans_fd { -	struct file *rd; -	struct file *wr; -	struct p9_conn *conn; -}; -  /*    * Option Parsing (code inspired by NFS code)    *  - a little lazy - parse all fd-transport options @@ -159,6 +145,20 @@ struct p9_conn {  	unsigned long wsched;  }; +/** + * struct p9_trans_fd - transport state + * @rd: reference to file to read from + * @wr: reference of file to write to + * @conn: connection state reference + * + */ + +struct p9_trans_fd { +	struct file *rd; +	struct file *wr; +	struct p9_conn conn; +}; +  static void p9_poll_workfn(struct work_struct *work);  static DEFINE_SPINLOCK(p9_poll_lock); @@ -212,15 +212,9 @@ static void p9_conn_cancel(struct p9_conn *m, int err)  	m->err = err;  	list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) { -		req->status = REQ_STATUS_ERROR; -		if (!req->t_err) -			req->t_err = err;  		list_move(&req->req_list, &cancel_list);  	}  	list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) { -		req->status = REQ_STATUS_ERROR; -		if (!req->t_err) -			req->t_err = err;  		list_move(&req->req_list, &cancel_list);  	}  	spin_unlock_irqrestore(&m->client->lock, flags); @@ -228,7 +222,9 @@ static void p9_conn_cancel(struct p9_conn *m, int err)  	list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) {  		p9_debug(P9_DEBUG_ERROR, "call back req %p\n", req);  		list_del(&req->req_list); -		p9_client_cb(m->client, req); +		if (!req->t_err) +			req->t_err = err; +		p9_client_cb(m->client, req, REQ_STATUS_ERROR);  	}  } @@ -244,10 +240,10 @@ p9_fd_poll(struct p9_client *client, struct poll_table_struct *pt)  	if (!ts)  		return -EREMOTEIO; -	if (!ts->rd->f_op || !ts->rd->f_op->poll) +	if (!ts->rd->f_op->poll)  		return -EIO; -	if (!ts->wr->f_op || !ts->wr->f_op->poll) +	if (!ts->wr->f_op->poll)  		return -EIO;  	ret = ts->rd->f_op->poll(ts->rd, pt); @@ -302,6 +298,7 @@ static void p9_read_work(struct work_struct *work)  {  	int n, err;  	struct p9_conn *m; +	int status = REQ_STATUS_ERROR;  	m = container_of(work, struct p9_conn, rq); @@ -348,8 +345,7 @@ static void p9_read_work(struct work_struct *work)  			 "mux %p pkt: size: %d bytes tag: %d\n", m, n, tag);  		m->req = p9_tag_lookup(m->client, tag); -		if (!m->req || (m->req->status != REQ_STATUS_SENT && -					m->req->status != REQ_STATUS_FLSH)) { +		if (!m->req || (m->req->status != REQ_STATUS_SENT)) {  			p9_debug(P9_DEBUG_ERROR, "Unexpected packet tag %d\n",  				 tag);  			err = -EIO; @@ -375,10 +371,10 @@ static void p9_read_work(struct work_struct *work)  		p9_debug(P9_DEBUG_TRANS, "got new packet\n");  		spin_lock(&m->client->lock);  		if (m->req->status != REQ_STATUS_ERROR) -			m->req->status = REQ_STATUS_RCVD; +			status = REQ_STATUS_RCVD;  		list_del(&m->req->req_list);  		spin_unlock(&m->client->lock); -		p9_client_cb(m->client, m->req); +		p9_client_cb(m->client, m->req, status);  		m->rbuf = NULL;  		m->rpos = 0;  		m->rsize = 0; @@ -573,21 +569,19 @@ p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p)  }  /** - * p9_conn_create - allocate and initialize the per-session mux data + * p9_conn_create - initialize the per-session mux data   * @client: client instance   *   * Note: Creates the polling task if this is the first session.   */ -static struct p9_conn *p9_conn_create(struct p9_client *client) +static void p9_conn_create(struct p9_client *client)  {  	int n; -	struct p9_conn *m; +	struct p9_trans_fd *ts = client->trans; +	struct p9_conn *m = &ts->conn;  	p9_debug(P9_DEBUG_TRANS, "client %p msize %d\n", client, client->msize); -	m = kzalloc(sizeof(struct p9_conn), GFP_KERNEL); -	if (!m) -		return ERR_PTR(-ENOMEM);  	INIT_LIST_HEAD(&m->mux_list);  	m->client = client; @@ -609,8 +603,6 @@ static struct p9_conn *p9_conn_create(struct p9_client *client)  		p9_debug(P9_DEBUG_TRANS, "mux %p can write\n", m);  		set_bit(Wpending, &m->wsched);  	} - -	return m;  }  /** @@ -669,7 +661,7 @@ static int p9_fd_request(struct p9_client *client, struct p9_req_t *req)  {  	int n;  	struct p9_trans_fd *ts = client->trans; -	struct p9_conn *m = ts->conn; +	struct p9_conn *m = &ts->conn;  	p9_debug(P9_DEBUG_TRANS, "mux %p task %p tcall %p id %d\n",  		 m, current, req->tc, req->tc->id); @@ -704,14 +696,26 @@ static int p9_fd_cancel(struct p9_client *client, struct p9_req_t *req)  		list_del(&req->req_list);  		req->status = REQ_STATUS_FLSHD;  		ret = 0; -	} else if (req->status == REQ_STATUS_SENT) -		req->status = REQ_STATUS_FLSH; - +	}  	spin_unlock(&client->lock);  	return ret;  } +static int p9_fd_cancelled(struct p9_client *client, struct p9_req_t *req) +{ +	p9_debug(P9_DEBUG_TRANS, "client %p req %p\n", client, req); + +	/* we haven't received a response for oldreq, +	 * remove it from the list. +	 */ +	spin_lock(&client->lock); +	list_del(&req->req_list); +	spin_unlock(&client->lock); + +	return 0; +} +  /**   * parse_opts - parse mount options into p9_fd_opts structure   * @params: options string passed from mount @@ -780,7 +784,7 @@ static int parse_opts(char *params, struct p9_fd_opts *opts)  static int p9_fd_open(struct p9_client *client, int rfd, int wfd)  { -	struct p9_trans_fd *ts = kmalloc(sizeof(struct p9_trans_fd), +	struct p9_trans_fd *ts = kzalloc(sizeof(struct p9_trans_fd),  					   GFP_KERNEL);  	if (!ts)  		return -ENOMEM; @@ -806,9 +810,8 @@ static int p9_socket_open(struct p9_client *client, struct socket *csocket)  {  	struct p9_trans_fd *p;  	struct file *file; -	int ret; -	p = kmalloc(sizeof(struct p9_trans_fd), GFP_KERNEL); +	p = kzalloc(sizeof(struct p9_trans_fd), GFP_KERNEL);  	if (!p)  		return -ENOMEM; @@ -829,20 +832,12 @@ static int p9_socket_open(struct p9_client *client, struct socket *csocket)  	p->rd->f_flags |= O_NONBLOCK; -	p->conn = p9_conn_create(client); -	if (IS_ERR(p->conn)) { -		ret = PTR_ERR(p->conn); -		p->conn = NULL; -		kfree(p); -		sockfd_put(csocket); -		sockfd_put(csocket); -		return ret; -	} +	p9_conn_create(client);  	return 0;  }  /** - * p9_mux_destroy - cancels all pending requests and frees mux resources + * p9_mux_destroy - cancels all pending requests of mux   * @m: mux to destroy   *   */ @@ -859,7 +854,6 @@ static void p9_conn_destroy(struct p9_conn *m)  	p9_conn_cancel(m, -ECONNRESET);  	m->client = NULL; -	kfree(m);  }  /** @@ -881,7 +875,7 @@ static void p9_fd_close(struct p9_client *client)  	client->status = Disconnected; -	p9_conn_destroy(ts->conn); +	p9_conn_destroy(&ts->conn);  	if (ts->rd)  		fput(ts->rd); @@ -1033,14 +1027,7 @@ p9_fd_create(struct p9_client *client, const char *addr, char *args)  		return err;  	p = (struct p9_trans_fd *) client->trans; -	p->conn = p9_conn_create(client); -	if (IS_ERR(p->conn)) { -		err = PTR_ERR(p->conn); -		p->conn = NULL; -		fput(p->rd); -		fput(p->wr); -		return err; -	} +	p9_conn_create(client);  	return 0;  } @@ -1048,11 +1035,12 @@ p9_fd_create(struct p9_client *client, const char *addr, char *args)  static struct p9_trans_module p9_tcp_trans = {  	.name = "tcp",  	.maxsize = MAX_SOCK_BUF, -	.def = 1, +	.def = 0,  	.create = p9_fd_create_tcp,  	.close = p9_fd_close,  	.request = p9_fd_request,  	.cancel = p9_fd_cancel, +	.cancelled = p9_fd_cancelled,  	.owner = THIS_MODULE,  }; @@ -1064,6 +1052,7 @@ static struct p9_trans_module p9_unix_trans = {  	.close = p9_fd_close,  	.request = p9_fd_request,  	.cancel = p9_fd_cancel, +	.cancelled = p9_fd_cancelled,  	.owner = THIS_MODULE,  }; @@ -1075,6 +1064,7 @@ static struct p9_trans_module p9_fd_trans = {  	.close = p9_fd_close,  	.request = p9_fd_request,  	.cancel = p9_fd_cancel, +	.cancelled = p9_fd_cancelled,  	.owner = THIS_MODULE,  }; diff --git a/net/9p/trans_rdma.c b/net/9p/trans_rdma.c index 8f68df5d297..14ad43b5cf8 100644 --- a/net/9p/trans_rdma.c +++ b/net/9p/trans_rdma.c @@ -193,6 +193,8 @@ static int parse_opts(char *params, struct p9_rdma_opts *opts)  		if (!*p)  			continue;  		token = match_token(p, tokens, args); +		if (token == Opt_err) +			continue;  		r = match_int(&args[0], &option);  		if (r < 0) {  			p9_debug(P9_DEBUG_ERROR, @@ -305,8 +307,7 @@ handle_recv(struct p9_client *client, struct p9_trans_rdma *rdma,  	}  	req->rc = c->rc; -	req->status = REQ_STATUS_RCVD; -	p9_client_cb(client, req); +	p9_client_cb(client, req, REQ_STATUS_RCVD);  	return; @@ -511,6 +512,11 @@ dont_need_post_recv:  		goto send_error;  	} +	/* Mark request as `sent' *before* we actually send it, +	 * because doing if after could erase the REQ_STATUS_RCVD +	 * status in case of a very fast reply. +	 */ +	req->status = REQ_STATUS_SENT;  	err = ib_post_send(rdma->qp, &wr, &bad_wr);  	if (err)  		goto send_error; @@ -520,6 +526,7 @@ dont_need_post_recv:   /* Handle errors that happened during or while preparing the send: */   send_error: +	req->status = REQ_STATUS_ERROR;  	kfree(c);  	p9_debug(P9_DEBUG_ERROR, "Error %d in rdma_request()\n", err); @@ -582,12 +589,24 @@ static struct p9_trans_rdma *alloc_rdma(struct p9_rdma_opts *opts)  	return rdma;  } -/* its not clear to me we can do anything after send has been posted */  static int rdma_cancel(struct p9_client *client, struct p9_req_t *req)  { +	/* Nothing to do here. +	 * We will take care of it (if we have to) in rdma_cancelled() +	 */  	return 1;  } +/* A request has been fully flushed without a reply. + * That means we have posted one buffer in excess. + */ +static int rdma_cancelled(struct p9_client *client, struct p9_req_t *req) +{ +	struct p9_trans_rdma *rdma = client->trans; +	atomic_inc(&rdma->excess_rc); +	return 0; +} +  /**   * trans_create_rdma - Transport method for creating atransport instance   * @client: client instance @@ -721,6 +740,7 @@ static struct p9_trans_module p9_rdma_trans = {  	.close = rdma_close,  	.request = rdma_request,  	.cancel = rdma_cancel, +	.cancelled = rdma_cancelled,  };  /** diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index 990afab2be1..6940d8fe897 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c @@ -164,8 +164,7 @@ static void req_done(struct virtqueue *vq)  		p9_debug(P9_DEBUG_TRANS, ": rc %p\n", rc);  		p9_debug(P9_DEBUG_TRANS, ": lookup tag %d\n", rc->tag);  		req = p9_tag_lookup(chan->client, rc->tag); -		req->status = REQ_STATUS_RCVD; -		p9_client_cb(chan->client, req); +		p9_client_cb(chan->client, req, REQ_STATUS_RCVD);  	}  } @@ -340,7 +339,10 @@ static int p9_get_mapped_pages(struct virtio_chan *chan,  		int count = nr_pages;  		while (nr_pages) {  			s = rest_of_page(data); -			pages[index++] = kmap_to_page(data); +			if (is_vmalloc_addr(data)) +				pages[index++] = vmalloc_to_page(data); +			else +				pages[index++] = kmap_to_page(data);  			data += s;  			nr_pages--;  		} @@ -544,9 +546,7 @@ static int p9_virtio_probe(struct virtio_device *vdev)  	chan->inuse = false;  	if (virtio_has_feature(vdev, VIRTIO_9P_MOUNT_TAG)) { -		vdev->config->get(vdev, -				offsetof(struct virtio_9p_config, tag_len), -				&tag_len, sizeof(tag_len)); +		virtio_cread(vdev, struct virtio_9p_config, tag_len, &tag_len);  	} else {  		err = -EINVAL;  		goto out_free_vq; @@ -556,8 +556,9 @@ static int p9_virtio_probe(struct virtio_device *vdev)  		err = -ENOMEM;  		goto out_free_vq;  	} -	vdev->config->get(vdev, offsetof(struct virtio_9p_config, tag), -			tag, tag_len); + +	virtio_cread_bytes(vdev, offsetof(struct virtio_9p_config, tag), +			   tag, tag_len);  	chan->tag = tag;  	chan->tag_len = tag_len;  	err = sysfs_create_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr); @@ -699,7 +700,7 @@ static struct p9_trans_module p9_virtio_trans = {  	 * page in zero copy.  	 */  	.maxsize = PAGE_SIZE * (VIRTQUEUE_NUM - 3), -	.def = 0, +	.def = 1,  	.owner = THIS_MODULE,  };  | 
