diff options
Diffstat (limited to 'net/9p/protocol.c')
| -rw-r--r-- | net/9p/protocol.c | 154 | 
1 files changed, 76 insertions, 78 deletions
diff --git a/net/9p/protocol.c b/net/9p/protocol.c index 798beac7f10..ab9127ec5b7 100644 --- a/net/9p/protocol.c +++ b/net/9p/protocol.c @@ -37,46 +37,11 @@  #include <net/9p/client.h>  #include "protocol.h" +#include <trace/events/9p.h> +  static int  p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...); -#ifdef CONFIG_NET_9P_DEBUG -void -p9pdu_dump(int way, struct p9_fcall *pdu) -{ -	int i, n; -	u8 *data = pdu->sdata; -	int datalen = pdu->size; -	char buf[255]; -	int buflen = 255; - -	i = n = 0; -	if (datalen > (buflen-16)) -		datalen = buflen-16; -	while (i < datalen) { -		n += scnprintf(buf + n, buflen - n, "%02x ", data[i]); -		if (i%4 == 3) -			n += scnprintf(buf + n, buflen - n, " "); -		if (i%32 == 31) -			n += scnprintf(buf + n, buflen - n, "\n"); - -		i++; -	} -	n += scnprintf(buf + n, buflen - n, "\n"); - -	if (way) -		P9_DPRINTK(P9_DEBUG_PKT, "[[[(%d) %s\n", datalen, buf); -	else -		P9_DPRINTK(P9_DEBUG_PKT, "]]](%d) %s\n", datalen, buf); -} -#else -void -p9pdu_dump(int way, struct p9_fcall *pdu) -{ -} -#endif -EXPORT_SYMBOL(p9pdu_dump); -  void p9stat_free(struct p9_wstat *stbuf)  {  	kfree(stbuf->name); @@ -87,7 +52,7 @@ void p9stat_free(struct p9_wstat *stbuf)  }  EXPORT_SYMBOL(p9stat_free); -static size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size) +size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size)  {  	size_t len = min(pdu->size - pdu->offset, size);  	memcpy(data, &pdu->sdata[pdu->offset], len); @@ -120,6 +85,8 @@ pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)  	d - int32_t  	q - int64_t  	s - string +	u - numeric uid +	g - numeric gid  	S - stat  	Q - qid  	D - data blob (int32_t size followed by void *, results are not freed) @@ -178,29 +145,46 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,  			break;  		case 's':{  				char **sptr = va_arg(ap, char **); -				int16_t len; -				int size; +				uint16_t len;  				errcode = p9pdu_readf(pdu, proto_version,  								"w", &len);  				if (errcode)  					break; -				size = max_t(int16_t, len, 0); - -				*sptr = kmalloc(size + 1, GFP_KERNEL); +				*sptr = kmalloc(len + 1, GFP_NOFS);  				if (*sptr == NULL) {  					errcode = -EFAULT;  					break;  				} -				if (pdu_read(pdu, *sptr, size)) { +				if (pdu_read(pdu, *sptr, len)) {  					errcode = -EFAULT;  					kfree(*sptr);  					*sptr = NULL;  				} else -					(*sptr)[size] = 0; +					(*sptr)[len] = 0;  			}  			break; +		case 'u': { +				kuid_t *uid = va_arg(ap, kuid_t *); +				__le32 le_val; +				if (pdu_read(pdu, &le_val, sizeof(le_val))) { +					errcode = -EFAULT; +					break; +				} +				*uid = make_kuid(&init_user_ns, +						 le32_to_cpu(le_val)); +			} break; +		case 'g': { +				kgid_t *gid = va_arg(ap, kgid_t *); +				__le32 le_val; +				if (pdu_read(pdu, &le_val, sizeof(le_val))) { +					errcode = -EFAULT; +					break; +				} +				*gid = make_kgid(&init_user_ns, +						 le32_to_cpu(le_val)); +			} break;  		case 'Q':{  				struct p9_qid *qid =  				    va_arg(ap, struct p9_qid *); @@ -215,11 +199,12 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,  				    va_arg(ap, struct p9_wstat *);  				memset(stbuf, 0, sizeof(struct p9_wstat)); -				stbuf->n_uid = stbuf->n_gid = stbuf->n_muid = -									-1; +				stbuf->n_uid = stbuf->n_muid = INVALID_UID; +				stbuf->n_gid = INVALID_GID; +  				errcode =  				    p9pdu_readf(pdu, proto_version, -						"wwdQdddqssss?sddd", +						"wwdQdddqssss?sugu",  						&stbuf->size, &stbuf->type,  						&stbuf->dev, &stbuf->qid,  						&stbuf->mode, &stbuf->atime, @@ -234,21 +219,21 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,  			}  			break;  		case 'D':{ -				int32_t *count = va_arg(ap, int32_t *); +				uint32_t *count = va_arg(ap, uint32_t *);  				void **data = va_arg(ap, void **);  				errcode =  				    p9pdu_readf(pdu, proto_version, "d", count);  				if (!errcode) {  					*count = -					    min_t(int32_t, *count, +					    min_t(uint32_t, *count,  						  pdu->size - pdu->offset);  					*data = &pdu->sdata[pdu->offset];  				}  			}  			break;  		case 'T':{ -				int16_t *nwname = va_arg(ap, int16_t *); +				uint16_t *nwname = va_arg(ap, uint16_t *);  				char ***wnames = va_arg(ap, char ***);  				errcode = p9pdu_readf(pdu, proto_version, @@ -256,7 +241,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,  				if (!errcode) {  					*wnames =  					    kmalloc(sizeof(char *) * *nwname, -						    GFP_KERNEL); +						    GFP_NOFS);  					if (!*wnames)  						errcode = -ENOMEM;  				} @@ -300,7 +285,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,  					*wqids =  					    kmalloc(*nwqid *  						    sizeof(struct p9_qid), -						    GFP_KERNEL); +						    GFP_NOFS);  					if (*wqids == NULL)  						errcode = -ENOMEM;  				} @@ -332,7 +317,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,  				memset(stbuf, 0, sizeof(struct p9_stat_dotl));  				errcode =  				    p9pdu_readf(pdu, proto_version, -					"qQdddqqqqqqqqqqqqqqq", +					"qQdugqqqqqqqqqqqqqqq",  					&stbuf->st_result_mask,  					&stbuf->qid,  					&stbuf->st_mode, @@ -404,9 +389,10 @@ p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,  			break;  		case 's':{  				const char *sptr = va_arg(ap, const char *); -				int16_t len = 0; +				uint16_t len = 0;  				if (sptr) -					len = min_t(int16_t, strlen(sptr), USHRT_MAX); +					len = min_t(size_t, strlen(sptr), +								USHRT_MAX);  				errcode = p9pdu_writef(pdu, proto_version,  								"w", len); @@ -414,6 +400,20 @@ p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,  					errcode = -EFAULT;  			}  			break; +		case 'u': { +				kuid_t uid = va_arg(ap, kuid_t); +				__le32 val = cpu_to_le32( +						from_kuid(&init_user_ns, uid)); +				if (pdu_write(pdu, &val, sizeof(val))) +					errcode = -EFAULT; +			} break; +		case 'g': { +				kgid_t gid = va_arg(ap, kgid_t); +				__le32 val = cpu_to_le32( +						from_kgid(&init_user_ns, gid)); +				if (pdu_write(pdu, &val, sizeof(val))) +					errcode = -EFAULT; +			} break;  		case 'Q':{  				const struct p9_qid *qid =  				    va_arg(ap, const struct p9_qid *); @@ -427,7 +427,7 @@ p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,  				    va_arg(ap, const struct p9_wstat *);  				errcode =  				    p9pdu_writef(pdu, proto_version, -						 "wwdQdddqssss?sddd", +						 "wwdQdddqssss?sugu",  						 stbuf->size, stbuf->type,  						 stbuf->dev, &stbuf->qid,  						 stbuf->mode, stbuf->atime, @@ -438,7 +438,7 @@ p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,  						 stbuf->n_gid, stbuf->n_muid);  			} break;  		case 'D':{ -				int32_t count = va_arg(ap, int32_t); +				uint32_t count = va_arg(ap, uint32_t);  				const void *data = va_arg(ap, const void *);  				errcode = p9pdu_writef(pdu, proto_version, "d", @@ -458,7 +458,7 @@ p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,  			}  			break;  		case 'T':{ -				int16_t nwname = va_arg(ap, int); +				uint16_t nwname = va_arg(ap, int);  				const char **wnames = va_arg(ap, const char **);  				errcode = p9pdu_writef(pdu, proto_version, "w", @@ -505,7 +505,7 @@ p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,  							struct p9_iattr_dotl *);  				errcode = p9pdu_writef(pdu, proto_version, -							"ddddqqqqq", +							"ddugqqqqq",  							p9attr->valid,  							p9attr->mode,  							p9attr->uid, @@ -559,7 +559,7 @@ p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)  	return ret;  } -int p9stat_read(char *buf, int len, struct p9_wstat *st, int proto_version) +int p9stat_read(struct p9_client *clnt, char *buf, int len, struct p9_wstat *st)  {  	struct p9_fcall fake_pdu;  	int ret; @@ -569,10 +569,10 @@ int p9stat_read(char *buf, int len, struct p9_wstat *st, int proto_version)  	fake_pdu.sdata = buf;  	fake_pdu.offset = 0; -	ret = p9pdu_readf(&fake_pdu, proto_version, "S", st); +	ret = p9pdu_readf(&fake_pdu, clnt->proto_version, "S", st);  	if (ret) { -		P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret); -		p9pdu_dump(1, &fake_pdu); +		p9_debug(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret); +		trace_9p_protocol_dump(clnt, &fake_pdu);  	}  	return ret; @@ -581,10 +581,11 @@ EXPORT_SYMBOL(p9stat_read);  int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type)  { +	pdu->id = type;  	return p9pdu_writef(pdu, 0, "dbw", 0, type, tag);  } -int p9pdu_finalize(struct p9_fcall *pdu) +int p9pdu_finalize(struct p9_client *clnt, struct p9_fcall *pdu)  {  	int size = pdu->size;  	int err; @@ -593,13 +594,9 @@ int p9pdu_finalize(struct p9_fcall *pdu)  	err = p9pdu_writef(pdu, 0, "d", size);  	pdu->size = size; -#ifdef CONFIG_NET_9P_DEBUG -	if ((p9_debug_level & P9_DEBUG_PKT) == P9_DEBUG_PKT) -		p9pdu_dump(0, pdu); -#endif - -	P9_DPRINTK(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", pdu->size, -							pdu->id, pdu->tag); +	trace_9p_protocol_dump(clnt, pdu); +	p9_debug(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", +		 pdu->size, pdu->id, pdu->tag);  	return err;  } @@ -610,8 +607,8 @@ void p9pdu_reset(struct p9_fcall *pdu)  	pdu->size = 0;  } -int p9dirent_read(char *buf, int len, struct p9_dirent *dirent, -						int proto_version) +int p9dirent_read(struct p9_client *clnt, char *buf, int len, +		  struct p9_dirent *dirent)  {  	struct p9_fcall fake_pdu;  	int ret; @@ -622,15 +619,16 @@ int p9dirent_read(char *buf, int len, struct p9_dirent *dirent,  	fake_pdu.sdata = buf;  	fake_pdu.offset = 0; -	ret = p9pdu_readf(&fake_pdu, proto_version, "Qqbs", &dirent->qid, -			&dirent->d_off, &dirent->d_type, &nameptr); +	ret = p9pdu_readf(&fake_pdu, clnt->proto_version, "Qqbs", &dirent->qid, +			  &dirent->d_off, &dirent->d_type, &nameptr);  	if (ret) { -		P9_DPRINTK(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret); -		p9pdu_dump(1, &fake_pdu); +		p9_debug(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret); +		trace_9p_protocol_dump(clnt, &fake_pdu);  		goto out;  	}  	strcpy(dirent->d_name, nameptr); +	kfree(nameptr);  out:  	return fake_pdu.offset;  | 
