Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
[cascardo/linux.git] / net / 9p / protocol.c
index 43e9822..dcd7666 100644 (file)
@@ -27,6 +27,8 @@
 
 #include <linux/module.h>
 #include <linux/errno.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
 #include <net/9p/9p.h>
 #include <net/9p/client.h>
 #include "protocol.h"
 static int
 p9pdu_writef(struct p9_fcall *pdu, int optional, 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);
@@ -77,6 +116,18 @@ static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size)
        return size - len;
 }
 
+static size_t
+pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)
+{
+       size_t len = MIN(pdu->capacity - pdu->size, size);
+       int err = copy_from_user(&pdu->sdata[pdu->size], udata, len);
+       if (err)
+               printk(KERN_WARNING "pdu_write_u returning: %d\n", err);
+
+       pdu->size += len;
+       return size - len;
+}
+
 /*
        b - int8_t
        w - int16_t
@@ -135,7 +186,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
                        }
                        break;
                case 's':{
-                               char **ptr = va_arg(ap, char **);
+                               char **sptr = va_arg(ap, char **);
                                int16_t len;
                                int size;
 
@@ -145,17 +196,17 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
 
                                size = MAX(len, 0);
 
-                               *ptr = kmalloc(size + 1, GFP_KERNEL);
-                               if (*ptr == NULL) {
+                               *sptr = kmalloc(size + 1, GFP_KERNEL);
+                               if (*sptr == NULL) {
                                        errcode = -EFAULT;
                                        break;
                                }
-                               if (pdu_read(pdu, *ptr, size)) {
+                               if (pdu_read(pdu, *sptr, size)) {
                                        errcode = -EFAULT;
-                                       kfree(*ptr);
-                                       *ptr = NULL;
+                                       kfree(*sptr);
+                                       *sptr = NULL;
                                } else
-                                       (*ptr)[size] = 0;
+                                       (*sptr)[size] = 0;
                        }
                        break;
                case 'Q':{
@@ -171,10 +222,9 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
                                struct p9_wstat *stbuf =
                                    va_arg(ap, struct p9_wstat *);
 
-                               stbuf->extension = NULL;
+                               memset(stbuf, 0, sizeof(struct p9_wstat));
                                stbuf->n_uid = stbuf->n_gid = stbuf->n_muid =
-                                   -1;
-
+                                                                       -1;
                                errcode =
                                    p9pdu_readf(pdu, optional,
                                                "wwdQdddqssss?sddd",
@@ -330,14 +380,13 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
                        }
                        break;
                case 's':{
-                               const char *ptr = va_arg(ap, const char *);
+                               const char *sptr = va_arg(ap, const char *);
                                int16_t len = 0;
-
-                               if (ptr)
-                                       len = MIN(strlen(ptr), USHORT_MAX);
+                               if (sptr)
+                                       len = MIN(strlen(sptr), USHORT_MAX);
 
                                errcode = p9pdu_writef(pdu, optional, "w", len);
-                               if (!errcode && pdu_write(pdu, ptr, len))
+                               if (!errcode && pdu_write(pdu, sptr, len))
                                        errcode = -EFAULT;
                        }
                        break;
@@ -356,7 +405,7 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
                                    p9pdu_writef(pdu, optional,
                                                 "wwdQdddqssss?sddd",
                                                 stbuf->size, stbuf->type,
-                                                stbuf->dev, stbuf->qid,
+                                                stbuf->dev, &stbuf->qid,
                                                 stbuf->mode, stbuf->atime,
                                                 stbuf->mtime, stbuf->length,
                                                 stbuf->name, stbuf->uid,
@@ -374,6 +423,16 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
                                        errcode = -EFAULT;
                        }
                        break;
+               case 'U':{
+                               int32_t count = va_arg(ap, int32_t);
+                               const char __user *udata =
+                                               va_arg(ap, const void __user *);
+                               errcode =
+                                   p9pdu_writef(pdu, optional, "d", count);
+                               if (!errcode && pdu_write_u(pdu, udata, count))
+                                       errcode = -EFAULT;
+                       }
+                       break;
                case 'T':{
                                int16_t nwname = va_arg(ap, int);
                                const char **wnames = va_arg(ap, const char **);
@@ -455,3 +514,54 @@ p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...)
 
        return ret;
 }
+
+int p9stat_read(char *buf, int len, struct p9_wstat *st, int dotu)
+{
+       struct p9_fcall fake_pdu;
+       int ret;
+
+       fake_pdu.size = len;
+       fake_pdu.capacity = len;
+       fake_pdu.sdata = buf;
+       fake_pdu.offset = 0;
+
+       ret = p9pdu_readf(&fake_pdu, dotu, "S", st);
+       if (ret) {
+               P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
+               p9pdu_dump(1, &fake_pdu);
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(p9stat_read);
+
+int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type)
+{
+       return p9pdu_writef(pdu, 0, "dbw", 0, type, tag);
+}
+
+int p9pdu_finalize(struct p9_fcall *pdu)
+{
+       int size = pdu->size;
+       int err;
+
+       pdu->size = 0;
+       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);
+
+       return err;
+}
+
+void p9pdu_reset(struct p9_fcall *pdu)
+{
+       pdu->offset = 0;
+       pdu->size = 0;
+}