diff options
Diffstat (limited to 'net/9p/client.c')
| -rw-r--r-- | net/9p/client.c | 164 | 
1 files changed, 120 insertions, 44 deletions
diff --git a/net/9p/client.c b/net/9p/client.c index a848bca9fbff..347ec0cd2718 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -229,10 +229,23 @@ static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag)  			return ERR_PTR(-ENOMEM);  		}  		init_waitqueue_head(req->wq); -		req->tc = kmalloc(sizeof(struct p9_fcall)+c->msize, -								GFP_KERNEL); -		req->rc = kmalloc(sizeof(struct p9_fcall)+c->msize, -								GFP_KERNEL); +		if ((c->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) == +				P9_TRANS_PREF_PAYLOAD_SEP) { +			int alloc_msize = min(c->msize, 4096); +			req->tc = kmalloc(sizeof(struct p9_fcall)+alloc_msize, +					GFP_KERNEL); +			req->tc->capacity = alloc_msize; +			req->rc = kmalloc(sizeof(struct p9_fcall)+alloc_msize, +					GFP_KERNEL); +			req->rc->capacity = alloc_msize; +		} else { +			req->tc = kmalloc(sizeof(struct p9_fcall)+c->msize, +					GFP_KERNEL); +			req->tc->capacity = c->msize; +			req->rc = kmalloc(sizeof(struct p9_fcall)+c->msize, +					GFP_KERNEL); +			req->rc->capacity = c->msize; +		}  		if ((!req->tc) || (!req->rc)) {  			printk(KERN_ERR "Couldn't grow tag array\n");  			kfree(req->tc); @@ -243,9 +256,7 @@ static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag)  			return ERR_PTR(-ENOMEM);  		}  		req->tc->sdata = (char *) req->tc + sizeof(struct p9_fcall); -		req->tc->capacity = c->msize;  		req->rc->sdata = (char *) req->rc + sizeof(struct p9_fcall); -		req->rc->capacity = c->msize;  	}  	p9pdu_reset(req->tc); @@ -443,6 +454,7 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)  {  	int8_t type;  	int err; +	int ecode;  	err = p9_parse_header(req->rc, NULL, &type, NULL, 0);  	if (err) { @@ -450,36 +462,53 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)  		return err;  	} -	if (type == P9_RERROR || type == P9_RLERROR) { -		int ecode; - -		if (!p9_is_proto_dotl(c)) { -			char *ename; +	if (type != P9_RERROR && type != P9_RLERROR) +		return 0; -			err = p9pdu_readf(req->rc, c->proto_version, "s?d", -								&ename, &ecode); -			if (err) -				goto out_err; +	if (!p9_is_proto_dotl(c)) { +		char *ename; -			if (p9_is_proto_dotu(c)) -				err = -ecode; +		if (req->tc->pbuf_size) { +			/* Handle user buffers */ +			size_t len = req->rc->size - req->rc->offset; +			if (req->tc->pubuf) { +				/* User Buffer */ +				err = copy_from_user( +					&req->rc->sdata[req->rc->offset], +					req->tc->pubuf, len); +				if (err) { +					err = -EFAULT; +					goto out_err; +				} +			} else { +				/* Kernel Buffer */ +				memmove(&req->rc->sdata[req->rc->offset], +						req->tc->pkbuf, len); +			} +		} +		err = p9pdu_readf(req->rc, c->proto_version, "s?d", +				&ename, &ecode); +		if (err) +			goto out_err; -			if (!err || !IS_ERR_VALUE(err)) { -				err = p9_errstr2errno(ename, strlen(ename)); +		if (p9_is_proto_dotu(c)) +			err = -ecode; -				P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, ename); +		if (!err || !IS_ERR_VALUE(err)) { +			err = p9_errstr2errno(ename, strlen(ename)); -				kfree(ename); -			} -		} else { -			err = p9pdu_readf(req->rc, c->proto_version, "d", &ecode); -			err = -ecode; +			P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, +					ename); -			P9_DPRINTK(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode); +			kfree(ename);  		} +	} else { +		err = p9pdu_readf(req->rc, c->proto_version, "d", &ecode); +		err = -ecode; + +		P9_DPRINTK(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode); +	} -	} else -		err = 0;  	return err; @@ -1191,6 +1220,27 @@ error:  }  EXPORT_SYMBOL(p9_client_fsync); +int p9_client_sync_fs(struct p9_fid *fid) +{ +	int err = 0; +	struct p9_req_t *req; +	struct p9_client *clnt; + +	P9_DPRINTK(P9_DEBUG_9P, ">>> TSYNC_FS fid %d\n", fid->fid); + +	clnt = fid->clnt; +	req = p9_client_rpc(clnt, P9_TSYNCFS, "d", fid->fid); +	if (IS_ERR(req)) { +		err = PTR_ERR(req); +		goto error; +	} +	P9_DPRINTK(P9_DEBUG_9P, "<<< RSYNCFS fid %d\n", fid->fid); +	p9_free_req(clnt, req); +error: +	return err; +} +EXPORT_SYMBOL(p9_client_sync_fs); +  int p9_client_clunk(struct p9_fid *fid)  {  	int err; @@ -1270,7 +1320,15 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,  	if (count < rsize)  		rsize = count; -	req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, rsize); +	/* Don't bother zerocopy form small IO (< 1024) */ +	if (((clnt->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) == +			P9_TRANS_PREF_PAYLOAD_SEP) && (rsize > 1024)) { +		req = p9_client_rpc(clnt, P9_TREAD, "dqE", fid->fid, offset, +				rsize, data, udata); +	} else { +		req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, +				rsize); +	}  	if (IS_ERR(req)) {  		err = PTR_ERR(req);  		goto error; @@ -1284,13 +1342,15 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,  	P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count); -	if (data) { -		memmove(data, dataptr, count); -	} else { -		err = copy_to_user(udata, dataptr, count); -		if (err) { -			err = -EFAULT; -			goto free_and_error; +	if (!req->tc->pbuf_size) { +		if (data) { +			memmove(data, dataptr, count); +		} else { +			err = copy_to_user(udata, dataptr, count); +			if (err) { +				err = -EFAULT; +				goto free_and_error; +			}  		}  	}  	p9_free_req(clnt, req); @@ -1323,12 +1383,21 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,  	if (count < rsize)  		rsize = count; -	if (data) -		req = p9_client_rpc(clnt, P9_TWRITE, "dqD", fid->fid, offset, -								rsize, data); -	else -		req = p9_client_rpc(clnt, P9_TWRITE, "dqU", fid->fid, offset, -								rsize, udata); + +	/* Don't bother zerocopy form small IO (< 1024) */ +	if (((clnt->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) == +				P9_TRANS_PREF_PAYLOAD_SEP) && (rsize > 1024)) { +		req = p9_client_rpc(clnt, P9_TWRITE, "dqE", fid->fid, offset, +				rsize, data, udata); +	} else { + +		if (data) +			req = p9_client_rpc(clnt, P9_TWRITE, "dqD", fid->fid, +					offset, rsize, data); +		else +			req = p9_client_rpc(clnt, P9_TWRITE, "dqU", fid->fid, +					offset, rsize, udata); +	}  	if (IS_ERR(req)) {  		err = PTR_ERR(req);  		goto error; @@ -1716,7 +1785,14 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset)  	if (count < rsize)  		rsize = count; -	req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid, offset, rsize); +	if ((clnt->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) == +			P9_TRANS_PREF_PAYLOAD_SEP) { +		req = p9_client_rpc(clnt, P9_TREADDIR, "dqF", fid->fid, +				offset, rsize, data); +	} else { +		req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid, +				offset, rsize); +	}  	if (IS_ERR(req)) {  		err = PTR_ERR(req);  		goto error; @@ -1730,7 +1806,7 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset)  	P9_DPRINTK(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count); -	if (data) +	if (!req->tc->pbuf_size && data)  		memmove(data, dataptr, count);  	p9_free_req(clnt, req);  | 
