net/9p: Handle error in zero copy request correctly for 9p2000.u
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Mon, 20 May 2013 17:35:15 +0000 (23:05 +0530)
committerEric Van Hensbergen <ericvh@gmail.com>
Tue, 28 May 2013 14:28:42 +0000 (09:28 -0500)
For zero copy request, error will be encoded in the user space buffer.
So copy the error code correctly using copy_from_user. Here we use the
extra bytes we allocate for zero copy request. If total error details
are more than P9_ZC_HDR_SZ - 7 bytes, we return -EFAULT. The patch also
avoid a memory allocation in the error path.

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
net/9p/client.c

index 5e94dab..01f1779 100644 (file)
@@ -562,36 +562,19 @@ static int p9_check_zc_errors(struct p9_client *c, struct p9_req_t *req,
 
        if (!p9_is_proto_dotl(c)) {
                /* Error is reported in string format */
-               uint16_t len;
-               /* 7 = header size for RERROR, 2 is the size of string len; */
-               int inline_len = in_hdrlen - (7 + 2);
+               int len;
+               /* 7 = header size for RERROR; */
+               int inline_len = in_hdrlen - 7;
 
-               /* Read the size of error string */
-               err = p9pdu_readf(req->rc, c->proto_version, "w", &len);
-               if (err)
-                       goto out_err;
-
-               ename = kmalloc(len + 1, GFP_NOFS);
-               if (!ename) {
-                       err = -ENOMEM;
+               len =  req->rc->size - req->rc->offset;
+               if (len > (P9_ZC_HDR_SZ - 7)) {
+                       err = -EFAULT;
                        goto out_err;
                }
-               if (len <= inline_len) {
-                       /* We have error in protocol buffer itself */
-                       if (pdu_read(req->rc, ename, len)) {
-                               err = -EFAULT;
-                               goto out_free;
 
-                       }
-               } else {
-                       /*
-                        *  Part of the data is in user space buffer.
-                        */
-                       if (pdu_read(req->rc, ename, inline_len)) {
-                               err = -EFAULT;
-                               goto out_free;
-
-                       }
+               ename = &req->rc->sdata[req->rc->offset];
+               if (len > inline_len) {
+                       /* We have error in external buffer */
                        if (kern_buf) {
                                memcpy(ename + inline_len, uidata,
                                       len - inline_len);
@@ -600,19 +583,19 @@ static int p9_check_zc_errors(struct p9_client *c, struct p9_req_t *req,
                                                     uidata, len - inline_len);
                                if (err) {
                                        err = -EFAULT;
-                                       goto out_free;
+                                       goto out_err;
                                }
                        }
                }
-               ename[len] = 0;
-               if (p9_is_proto_dotu(c)) {
-                       /* For dotu we also have error code */
-                       err = p9pdu_readf(req->rc,
-                                         c->proto_version, "d", &ecode);
-                       if (err)
-                               goto out_free;
+               ename = NULL;
+               err = p9pdu_readf(req->rc, c->proto_version, "s?d",
+                                 &ename, &ecode);
+               if (err)
+                       goto out_err;
+
+               if (p9_is_proto_dotu(c))
                        err = -ecode;
-               }
+
                if (!err || !IS_ERR_VALUE(err)) {
                        err = p9_errstr2errno(ename, strlen(ename));
 
@@ -628,8 +611,6 @@ static int p9_check_zc_errors(struct p9_client *c, struct p9_req_t *req,
        }
        return err;
 
-out_free:
-       kfree(ename);
 out_err:
        p9_debug(P9_DEBUG_ERROR, "couldn't parse error%d\n", err);
        return err;