+ }
+
+ return bufp->p - bufp->sp;
+}
+
+static inline void v9fs_put_int8(struct cbuf *bufp, u8 val, u8 * p)
+{
+ *p = val;
+ buf_put_int8(bufp, val);
+}
+
+static inline void v9fs_put_int16(struct cbuf *bufp, u16 val, u16 * p)
+{
+ *p = val;
+ buf_put_int16(bufp, val);
+}
+
+static inline void v9fs_put_int32(struct cbuf *bufp, u32 val, u32 * p)
+{
+ *p = val;
+ buf_put_int32(bufp, val);
+}
+
+static inline void v9fs_put_int64(struct cbuf *bufp, u64 val, u64 * p)
+{
+ *p = val;
+ buf_put_int64(bufp, val);
+}
+
+static inline void
+v9fs_put_str(struct cbuf *bufp, char *data, struct v9fs_str *str)
+{
+ if (data) {
+ str->len = strlen(data);
+ str->str = bufp->p;
+ } else {
+ str->len = 0;
+ str->str = NULL;
+ }
+
+ buf_put_stringn(bufp, data, str->len);
+}
+
+static inline int
+v9fs_put_user_data(struct cbuf *bufp, const char __user * data, int count,
+ unsigned char **pdata)
+{
+ *pdata = buf_alloc(bufp, count);
+ return copy_from_user(*pdata, data, count);
+}
+
+static void
+v9fs_put_wstat(struct cbuf *bufp, struct v9fs_wstat *wstat,
+ struct v9fs_stat *stat, int statsz, int extended)
+{
+ v9fs_put_int16(bufp, statsz, &stat->size);
+ v9fs_put_int16(bufp, wstat->type, &stat->type);
+ v9fs_put_int32(bufp, wstat->dev, &stat->dev);
+ v9fs_put_int8(bufp, wstat->qid.type, &stat->qid.type);
+ v9fs_put_int32(bufp, wstat->qid.version, &stat->qid.version);
+ v9fs_put_int64(bufp, wstat->qid.path, &stat->qid.path);
+ v9fs_put_int32(bufp, wstat->mode, &stat->mode);
+ v9fs_put_int32(bufp, wstat->atime, &stat->atime);
+ v9fs_put_int32(bufp, wstat->mtime, &stat->mtime);
+ v9fs_put_int64(bufp, wstat->length, &stat->length);
+
+ v9fs_put_str(bufp, wstat->name, &stat->name);
+ v9fs_put_str(bufp, wstat->uid, &stat->uid);
+ v9fs_put_str(bufp, wstat->gid, &stat->gid);
+ v9fs_put_str(bufp, wstat->muid, &stat->muid);
+
+ if (extended) {
+ v9fs_put_str(bufp, wstat->extension, &stat->extension);
+ v9fs_put_int32(bufp, wstat->n_uid, &stat->n_uid);
+ v9fs_put_int32(bufp, wstat->n_gid, &stat->n_gid);
+ v9fs_put_int32(bufp, wstat->n_muid, &stat->n_muid);
+ }
+}
+
+static struct v9fs_fcall *
+v9fs_create_common(struct cbuf *bufp, u32 size, u8 id)
+{
+ struct v9fs_fcall *fc;
+
+ size += 4 + 1 + 2; /* size[4] id[1] tag[2] */
+ fc = kmalloc(sizeof(struct v9fs_fcall) + size, GFP_KERNEL);
+ if (!fc)
+ return ERR_PTR(-ENOMEM);
+
+ fc->sdata = (char *)fc + sizeof(*fc);
+
+ buf_init(bufp, (char *)fc->sdata, size);
+ v9fs_put_int32(bufp, size, &fc->size);
+ v9fs_put_int8(bufp, id, &fc->id);
+ v9fs_put_int16(bufp, V9FS_NOTAG, &fc->tag);
+
+ return fc;
+}
+
+void v9fs_set_tag(struct v9fs_fcall *fc, u16 tag)
+{
+ fc->tag = tag;
+ *(__le16 *) (fc->sdata + 5) = cpu_to_le16(tag);
+}
+
+struct v9fs_fcall *v9fs_create_tversion(u32 msize, char *version)
+{
+ int size;
+ struct v9fs_fcall *fc;
+ struct cbuf buffer;
+ struct cbuf *bufp = &buffer;
+
+ size = 4 + 2 + strlen(version); /* msize[4] version[s] */
+ fc = v9fs_create_common(bufp, size, TVERSION);
+ if (IS_ERR(fc))
+ goto error;
+
+ v9fs_put_int32(bufp, msize, &fc->params.tversion.msize);
+ v9fs_put_str(bufp, version, &fc->params.tversion.version);
+
+ if (buf_check_overflow(bufp)) {
+ kfree(fc);
+ fc = ERR_PTR(-ENOMEM);
+ }
+ error:
+ return fc;
+}
+
+struct v9fs_fcall *v9fs_create_tauth(u32 afid, char *uname, char *aname)
+{
+ int size;
+ struct v9fs_fcall *fc;
+ struct cbuf buffer;
+ struct cbuf *bufp = &buffer;
+
+ size = 4 + 2 + strlen(uname) + 2 + strlen(aname); /* afid[4] uname[s] aname[s] */
+ fc = v9fs_create_common(bufp, size, TAUTH);
+ if (IS_ERR(fc))
+ goto error;
+
+ v9fs_put_int32(bufp, afid, &fc->params.tauth.afid);
+ v9fs_put_str(bufp, uname, &fc->params.tauth.uname);
+ v9fs_put_str(bufp, aname, &fc->params.tauth.aname);
+
+ if (buf_check_overflow(bufp)) {
+ kfree(fc);
+ fc = ERR_PTR(-ENOMEM);
+ }
+ error:
+ return fc;
+}
+
+struct v9fs_fcall *
+v9fs_create_tattach(u32 fid, u32 afid, char *uname, char *aname)
+{
+ int size;
+ struct v9fs_fcall *fc;
+ struct cbuf buffer;
+ struct cbuf *bufp = &buffer;
+
+ size = 4 + 4 + 2 + strlen(uname) + 2 + strlen(aname); /* fid[4] afid[4] uname[s] aname[s] */
+ fc = v9fs_create_common(bufp, size, TATTACH);
+ if (IS_ERR(fc))
+ goto error;
+
+ v9fs_put_int32(bufp, fid, &fc->params.tattach.fid);
+ v9fs_put_int32(bufp, afid, &fc->params.tattach.afid);
+ v9fs_put_str(bufp, uname, &fc->params.tattach.uname);
+ v9fs_put_str(bufp, aname, &fc->params.tattach.aname);
+
+ error:
+ return fc;
+}
+
+struct v9fs_fcall *v9fs_create_tflush(u16 oldtag)
+{
+ int size;
+ struct v9fs_fcall *fc;
+ struct cbuf buffer;
+ struct cbuf *bufp = &buffer;
+
+ size = 2; /* oldtag[2] */
+ fc = v9fs_create_common(bufp, size, TFLUSH);
+ if (IS_ERR(fc))
+ goto error;
+
+ v9fs_put_int16(bufp, oldtag, &fc->params.tflush.oldtag);
+
+ if (buf_check_overflow(bufp)) {
+ kfree(fc);
+ fc = ERR_PTR(-ENOMEM);
+ }
+ error:
+ return fc;
+}
+
+struct v9fs_fcall *v9fs_create_twalk(u32 fid, u32 newfid, u16 nwname,
+ char **wnames)
+{
+ int i, size;
+ struct v9fs_fcall *fc;
+ struct cbuf buffer;
+ struct cbuf *bufp = &buffer;
+
+ if (nwname > V9FS_MAXWELEM) {
+ dprintk(DEBUG_ERROR, "nwname > %d\n", V9FS_MAXWELEM);
+ return NULL;
+ }
+
+ size = 4 + 4 + 2; /* fid[4] newfid[4] nwname[2] ... */
+ for (i = 0; i < nwname; i++) {
+ size += 2 + strlen(wnames[i]); /* wname[s] */
+ }
+
+ fc = v9fs_create_common(bufp, size, TWALK);
+ if (IS_ERR(fc))
+ goto error;