summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Van Hensbergen <ericvh@gmail.com>2008-10-16 08:30:07 -0500
committerEric Van Hensbergen <ericvh@gmail.com>2008-10-17 11:04:45 -0500
commit51a87c552dfd428e304c865e24ecbe091556f226 (patch)
tree6e9012962e6601b559dcf15ae3228647a8581a31
parentcb198131b0e7aba755ac164744536d461e86ab82 (diff)
9p: rework client code to use new protocol support functions
Now that the new protocol functions are in place, this patch switches the client code to using the new support code. Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
-rw-r--r--fs/9p/v9fs_vfs.h4
-rw-r--r--fs/9p/vfs_dir.c4
-rw-r--r--fs/9p/vfs_file.c2
-rw-r--r--fs/9p/vfs_inode.c38
-rw-r--r--fs/9p/vfs_super.c6
-rw-r--r--include/net/9p/9p.h7
-rw-r--r--include/net/9p/client.h7
-rw-r--r--net/9p/client.c931
-rw-r--r--net/9p/protocol.c85
-rw-r--r--net/9p/protocol.h5
-rw-r--r--net/9p/trans_fd.c62
-rw-r--r--net/9p/util.c4
12 files changed, 611 insertions, 544 deletions
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h
index 046cff377f10..c295ba786edd 100644
--- a/fs/9p/v9fs_vfs.h
+++ b/fs/9p/v9fs_vfs.h
@@ -46,10 +46,10 @@ extern struct dentry_operations v9fs_cached_dentry_operations;
struct inode *v9fs_get_inode(struct super_block *sb, int mode);
ino_t v9fs_qid2ino(struct p9_qid *qid);
-void v9fs_stat2inode(struct p9_stat *, struct inode *, struct super_block *);
+void v9fs_stat2inode(struct p9_wstat *, struct inode *, struct super_block *);
int v9fs_dir_release(struct inode *inode, struct file *filp);
int v9fs_file_open(struct inode *inode, struct file *file);
-void v9fs_inode2stat(struct inode *inode, struct p9_stat *stat);
+void v9fs_inode2stat(struct inode *inode, struct p9_wstat *stat);
void v9fs_dentry_release(struct dentry *);
int v9fs_uflags2omode(int uflags, int extended);
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
index d7d0ac5a2ca3..276aed625929 100644
--- a/fs/9p/vfs_dir.c
+++ b/fs/9p/vfs_dir.c
@@ -85,8 +85,8 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
return -ENOMEM;
while (1) {
- err = v9fs_file_readn(filp, statbuf, NULL, fid->rdir_fpos,
- buflen);
+ err = v9fs_file_readn(filp, statbuf, NULL, buflen,
+ fid->rdir_fpos);
if (err <= 0)
break;
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index 3fd28bbafc87..041c52692284 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -136,7 +136,7 @@ v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count,
int n, total;
struct p9_fid *fid = filp->private_data;
- P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
+ P9_DPRINTK(P9_DEBUG_VFS, "fid %d offset %llu count %d\n", fid->fid,
(long long unsigned) offset, count);
n = 0;
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index e83aa5ebe861..e96d84aafbe2 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -334,7 +334,7 @@ v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
{
int err, umode;
struct inode *ret;
- struct p9_stat *st;
+ struct p9_wstat *st;
ret = NULL;
st = p9_client_stat(fid);
@@ -417,6 +417,8 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
struct p9_fid *dfid, *ofid, *fid;
struct inode *inode;
+ P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
+
err = 0;
ofid = NULL;
fid = NULL;
@@ -424,6 +426,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
dfid = v9fs_fid_clone(dentry->d_parent);
if (IS_ERR(dfid)) {
err = PTR_ERR(dfid);
+ P9_DPRINTK(P9_DEBUG_VFS, "fid clone failed %d\n", err);
dfid = NULL;
goto error;
}
@@ -432,18 +435,22 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
ofid = p9_client_walk(dfid, 0, NULL, 1);
if (IS_ERR(ofid)) {
err = PTR_ERR(ofid);
+ P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
ofid = NULL;
goto error;
}
err = p9_client_fcreate(ofid, name, perm, mode, extension);
- if (err < 0)
+ if (err < 0) {
+ P9_DPRINTK(P9_DEBUG_VFS, "p9_client_fcreate failed %d\n", err);
goto error;
+ }
/* now walk from the parent so we can get unopened fid */
fid = p9_client_walk(dfid, 1, &name, 0);
if (IS_ERR(fid)) {
err = PTR_ERR(fid);
+ P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
fid = NULL;
goto error;
} else
@@ -453,6 +460,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
+ P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err);
goto error;
}
@@ -734,7 +742,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
int err;
struct v9fs_session_info *v9ses;
struct p9_fid *fid;
- struct p9_stat *st;
+ struct p9_wstat *st;
P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry);
err = -EPERM;
@@ -815,10 +823,9 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
*/
void
-v9fs_stat2inode(struct p9_stat *stat, struct inode *inode,
+v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
struct super_block *sb)
{
- int n;
char ext[32];
struct v9fs_session_info *v9ses = sb->s_fs_info;
@@ -842,11 +849,7 @@ v9fs_stat2inode(struct p9_stat *stat, struct inode *inode,
int major = -1;
int minor = -1;
- n = stat->extension.len;
- if (n > sizeof(ext)-1)
- n = sizeof(ext)-1;
- memmove(ext, stat->extension.str, n);
- ext[n] = 0;
+ strncpy(ext, stat->extension, sizeof(ext));
sscanf(ext, "%c %u %u", &type, &major, &minor);
switch (type) {
case 'c':
@@ -857,8 +860,8 @@ v9fs_stat2inode(struct p9_stat *stat, struct inode *inode,
break;
default:
P9_DPRINTK(P9_DEBUG_ERROR,
- "Unknown special type %c (%.*s)\n", type,
- stat->extension.len, stat->extension.str);
+ "Unknown special type %c %s\n", type,
+ stat->extension);
};
inode->i_rdev = MKDEV(major, minor);
} else
@@ -904,7 +907,7 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
struct v9fs_session_info *v9ses;
struct p9_fid *fid;
- struct p9_stat *st;
+ struct p9_wstat *st;
P9_DPRINTK(P9_DEBUG_VFS, " %s\n", dentry->d_name.name);
retval = -EPERM;
@@ -926,15 +929,10 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
}
/* copy extension buffer into buffer */
- if (st->extension.len < buflen)
- buflen = st->extension.len + 1;
-
- memmove(buffer, st->extension.str, buflen - 1);
- buffer[buflen-1] = 0;
+ strncpy(buffer, st->extension, buflen);
P9_DPRINTK(P9_DEBUG_VFS,
- "%s -> %.*s (%s)\n", dentry->d_name.name, st->extension.len,
- st->extension.str, buffer);
+ "%s -> %s (%s)\n", dentry->d_name.name, st->extension, buffer);
retval = buflen;
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index bf59c3960494..d6cb1a0ca724 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -111,7 +111,7 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
struct inode *inode = NULL;
struct dentry *root = NULL;
struct v9fs_session_info *v9ses = NULL;
- struct p9_stat *st = NULL;
+ struct p9_wstat *st = NULL;
int mode = S_IRWXUGO | S_ISVTX;
uid_t uid = current->fsuid;
gid_t gid = current->fsgid;
@@ -161,10 +161,14 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
sb->s_root = root;
root->d_inode->i_ino = v9fs_qid2ino(&st->qid);
+
v9fs_stat2inode(st, root->d_inode, sb);
+
v9fs_fid_add(root, fid);
+ p9stat_free(st);
kfree(st);
+P9_DPRINTK(P9_DEBUG_VFS, " return simple set mount\n");
return simple_set_mnt(mnt, sb);
release_sb:
diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h
index 46d0b8f8e5ec..56c15aee6e61 100644
--- a/include/net/9p/9p.h
+++ b/include/net/9p/9p.h
@@ -39,6 +39,7 @@
* @P9_DEBUG_TRANS: transport tracing
* @P9_DEBUG_SLABS: memory management tracing
* @P9_DEBUG_FCALL: verbose dump of protocol messages
+ * @P9_DEBUG_FID: fid allocation/deallocation tracking
*
* These flags are passed at mount time to turn on various levels of
* verbosity and tracing which will be output to the system logs.
@@ -53,13 +54,17 @@ enum p9_debug_flags {
P9_DEBUG_TRANS = (1<<6),
P9_DEBUG_SLABS = (1<<7),
P9_DEBUG_FCALL = (1<<8),
+ P9_DEBUG_FID = (1<<9),
};
extern unsigned int p9_debug_level;
#define P9_DPRINTK(level, format, arg...) \
do { \
- if ((p9_debug_level & level) == level) \
+ if (level == P9_DEBUG_9P) \
+ printk(KERN_NOTICE "(%8.8d) " \
+ format , task_pid_nr(current) , ## arg); \
+ else if ((p9_debug_level & level) == level) \
printk(KERN_NOTICE "-- %s (%d): " \
format , __func__, task_pid_nr(current) , ## arg); \
} while (0)
diff --git a/include/net/9p/client.h b/include/net/9p/client.h
index 475ef5cf1644..1e49b4d1030b 100644
--- a/include/net/9p/client.h
+++ b/include/net/9p/client.h
@@ -77,6 +77,7 @@ enum p9_req_status_t {
* struct p9_req_t - request slots
* @status: status of this request slot
* @t_err: transport error
+ * @flush_tag: tag of request being flushed (for flush requests)
* @wq: wait_queue for the client to block on for this request
* @tc: the request fcall structure
* @rc: the response fcall structure
@@ -97,10 +98,10 @@ enum p9_req_status_t {
struct p9_req_t {
int status;
int t_err;
+ u16 flush_tag;
wait_queue_head_t *wq;
struct p9_fcall *tc;
struct p9_fcall *rc;
- u16 flush_tag;
void *aux;
struct list_head req_list;
@@ -199,10 +200,12 @@ int p9_client_read(struct p9_fid *fid, char *data, char __user *udata,
u64 offset, u32 count);
int p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
u64 offset, u32 count);
-struct p9_stat *p9_client_stat(struct p9_fid *fid);
+struct p9_wstat *p9_client_stat(struct p9_fid *fid);
int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst);
struct p9_req_t *p9_tag_lookup(struct p9_client *, u16);
void p9_client_cb(struct p9_client *c, struct p9_req_t *req);
+void p9stat_free(struct p9_wstat *);
+
#endif /* NET_9P_CLIENT_H */
diff --git a/net/9p/client.c b/net/9p/client.c
index 6004fded6682..2a166bfb95a3 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -35,6 +35,7 @@
#include <linux/parser.h>
#include <net/9p/client.h>
#include <net/9p/transport.h>
+#include "protocol.h"
/*
* Client Option Parsing (code inspired by NFS code)
@@ -55,8 +56,8 @@ static const match_table_t tokens = {
{Opt_err, NULL},
};
-static int
-p9_client_rpc(struct p9_client *c, struct p9_fcall *tc, struct p9_fcall **rc);
+static struct p9_req_t *
+p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...);
/**
* v9fs_parse_options - parse mount options into session structure
@@ -138,10 +139,11 @@ static int parse_opts(char *opts, struct p9_client *clnt)
*
*/
-struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag)
+static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag)
{
unsigned long flags;
int row, col;
+ struct p9_req_t *req;
/* This looks up the original request by tag so we know which
* buffer to read the data into */
@@ -157,19 +159,11 @@ struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag)
if (!c->reqs[row]) {
printk(KERN_ERR "Couldn't grow tag array\n");
- BUG();
+ return ERR_PTR(-ENOMEM);
}
for (col = 0; col < P9_ROW_MAXTAG; col++) {
c->reqs[row][col].status = REQ_STATUS_IDLE;
- c->reqs[row][col].flush_tag = P9_NOTAG;
- c->reqs[row][col].wq = kmalloc(
- sizeof(wait_queue_head_t), GFP_ATOMIC);
- if (!c->reqs[row][col].wq) {
- printk(KERN_ERR
- "Couldn't grow tag array\n");
- BUG();
- }
- init_waitqueue_head(c->reqs[row][col].wq);
+ c->reqs[row][col].tc = NULL;
}
c->max_tag += P9_ROW_MAXTAG;
}
@@ -178,12 +172,39 @@ struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag)
row = tag / P9_ROW_MAXTAG;
col = tag % P9_ROW_MAXTAG;
- c->reqs[row][col].status = REQ_STATUS_ALLOC;
- c->reqs[row][col].flush_tag = P9_NOTAG;
+ req = &c->reqs[row][col];
+ if (!req->tc) {
+ req->wq = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL);
+ if (!req->wq) {
+ printk(KERN_ERR "Couldn't grow tag array\n");
+ 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 ((!req->tc) || (!req->rc)) {
+ printk(KERN_ERR "Couldn't grow tag array\n");
+ kfree(req->tc);
+ kfree(req->rc);
+ 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);
+ p9pdu_reset(req->rc);
+
+ req->flush_tag = 0;
+ req->tc->tag = tag-1;
+ req->status = REQ_STATUS_ALLOC;
return &c->reqs[row][col];
}
-EXPORT_SYMBOL(p9_tag_alloc);
/**
* p9_tag_lookup - lookup a request by tag
@@ -264,59 +285,34 @@ static void p9_tag_cleanup(struct p9_client *c)
/* free requests associated with tags */
for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) {
- for (col = 0; col < P9_ROW_MAXTAG; col++)
+ for (col = 0; col < P9_ROW_MAXTAG; col++) {
kfree(c->reqs[row][col].wq);
+ kfree(c->reqs[row][col].tc);
+ kfree(c->reqs[row][col].rc);
+ }
kfree(c->reqs[row]);
}
c->max_tag = 0;
}
/**
- * p9_client_flush - flush (cancel) a request
- * c: client state
- * req: request to cancel
- *
- * This sents a flush for a particular requests and links
- * the flush request to the original request. The current
- * code only supports a single flush request although the protocol
- * allows for multiple flush requests to be sent for a single request.
- *
- */
-
-static int p9_client_flush(struct p9_client *c, struct p9_req_t *req)
-{
- struct p9_fcall *tc, *rc = NULL;
- int err;
-
- P9_DPRINTK(P9_DEBUG_9P, "client %p tag %d\n", c, req->tc->tag);
-
- tc = p9_create_tflush(req->tc->tag);
- if (IS_ERR(tc))
- return PTR_ERR(tc);
-
- err = p9_client_rpc(c, tc, &rc);
-
- /* we don't free anything here because RPC isn't complete */
-
- return err;
-}
-
-/**
* p9_free_req - free a request and clean-up as necessary
* c: client state
* r: request to release
*
*/
-void p9_free_req(struct p9_client *c, struct p9_req_t *r)
+static void p9_free_req(struct p9_client *c, struct p9_req_t *r)
{
- r->flush_tag = P9_NOTAG;
+ int tag = r->tc->tag;
+ P9_DPRINTK(P9_DEBUG_MUX, "clnt %p req %p tag: %d\n", c, r, tag);
+
r->status = REQ_STATUS_IDLE;
- if (r->tc->tag != P9_NOTAG && p9_idpool_check(r->tc->tag, c->tagpool))
- p9_idpool_put(r->tc->tag, c->tagpool);
+ if (tag != P9_NOTAG && p9_idpool_check(tag, c->tagpool))
+ p9_idpool_put(tag, c->tagpool);
/* if this was a flush request we have to free response fcall */
- if (r->tc->id == P9_TFLUSH) {
+ if (r->rc->id == P9_RFLUSH) {
kfree(r->tc);
kfree(r->rc);
}
@@ -333,30 +329,28 @@ void p9_client_cb(struct p9_client *c, struct p9_req_t *req)
struct p9_req_t *other_req;
unsigned long flags;
- P9_DPRINTK(P9_DEBUG_MUX, ": %d\n", req->tc->tag);
+ P9_DPRINTK(P9_DEBUG_MUX, " tag %d\n", req->tc->tag);
if (req->status == REQ_STATUS_ERROR)
wake_up(req->wq);
- if (req->tc->id == P9_TFLUSH) { /* flush receive path */
- P9_DPRINTK(P9_DEBUG_MUX, "flush: %d\n", req->tc->tag);
+ if (req->flush_tag) { /* flush receive path */
+ P9_DPRINTK(P9_DEBUG_9P, "<<< RFLUSH %d\n", req->tc->tag);
spin_lock_irqsave(&c->lock, flags);
- other_req = p9_tag_lookup(c, req->tc->params.tflush.oldtag);
- if (other_req->flush_tag != req->tc->tag) /* stale flush */
+ other_req = p9_tag_lookup(c, req->flush_tag);
+ if (other_req->status != REQ_STATUS_FLSH) /* stale flush */
spin_unlock_irqrestore(&c->lock, flags);
else {
- BUG_ON(other_req->status != REQ_STATUS_FLSH);
other_req->status = REQ_STATUS_FLSHD;
spin_unlock_irqrestore(&c->lock, flags);
wake_up(other_req->wq);
}
p9_free_req(c, req);
} else { /* normal receive path */
- P9_DPRINTK(P9_DEBUG_MUX, "normal: %d\n", req->tc->tag);
+ P9_DPRINTK(P9_DEBUG_MUX, "normal: tag %d\n", req->tc->tag);
spin_lock_irqsave(&c->lock, flags);
if (req->status != REQ_STATUS_FLSHD)
req->status = REQ_STATUS_RCVD;
- req->flush_tag = P9_NOTAG;
spin_unlock_irqrestore(&c->lock, flags);
wake_up(req->wq);
P9_DPRINTK(P9_DEBUG_MUX, "wakeup: %d\n", req->tc->tag);
@@ -365,28 +359,164 @@ void p9_client_cb(struct p9_client *c, struct p9_req_t *req)
EXPORT_SYMBOL(p9_client_cb);
/**
+ * p9_parse_header - parse header arguments out of a packet
+ * @pdu: packet to parse
+ * @size: size of packet
+ * @type: type of request
+ * @tag: tag of packet
+ * @rewind: set if we need to rewind offset afterwards
+ */
+
+int
+p9_parse_header(struct p9_fcall *pdu, int32_t *size, int8_t *type, int16_t *tag,
+ int rewind)
+{
+ int8_t r_type;
+ int16_t r_tag;
+ int32_t r_size;
+ int offset = pdu->offset;
+ int err;
+
+ pdu->offset = 0;
+ if (pdu->size == 0)
+ pdu->size = 7;
+
+ err = p9pdu_readf(pdu, 0, "dbw", &r_size, &r_type, &r_tag);
+ if (err)
+ goto rewind_and_exit;
+
+ pdu->size = r_size;
+ pdu->id = r_type;
+ pdu->tag = r_tag;
+
+ P9_DPRINTK(P9_DEBUG_MUX, "pdu: type: %d tag: %d size=%d offset=%d\n",
+ pdu->id, pdu->tag, pdu->size, pdu->offset);
+
+ if (type)
+ *type = r_type;
+ if (tag)
+ *tag = r_tag;
+ if (size)
+ *size = r_size;
+
+
+rewind_and_exit:
+ if (rewind)
+ pdu->offset = offset;
+ return err;
+}
+EXPORT_SYMBOL(p9_parse_header);
+
+/**
+ * p9_check_errors - check 9p packet for error return and process it
+ * @c: current client instance
+ * @req: request to parse and check for error conditions
+ *
+ * returns error code if one is discovered, otherwise returns 0
+ *
+ * this will have to be more complicated if we have multiple
+ * error packet types
+ */
+
+static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
+{
+ int8_t type;
+ int err;
+
+ err = p9_parse_header(req->rc, NULL, &type, NULL, 0);
+ if (err) {
+ P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse header %d\n", err);
+ return err;
+ }
+
+ if (type == P9_RERROR) {
+ int ecode;
+ char *ename;
+
+ err = p9pdu_readf(req->rc, c->dotu, "s?d", &ename, &ecode);
+ if (err) {
+ P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n",
+ err);
+ return err;
+ }
+
+ if (c->dotu)
+ err = -ecode;
+
+ if (!err) {
+ err = p9_errstr2errno(ename, strlen(ename));
+
+ /* string match failed */
+ if (!err)
+ err = -ESERVERFAULT;
+ }
+
+ P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, ename);
+
+ kfree(ename);
+ } else
+ err = 0;
+
+ return err;
+}
+
+/**
+ * p9_client_flush - flush (cancel) a request
+ * c: client state
+ * req: request to cancel
+ *
+ * This sents a flush for a particular requests and links
+ * the flush request to the original request. The current
+ * code only supports a single flush request although the protocol
+ * allows for multiple flush requests to be sent for a single request.
+ *
+ */
+
+static int p9_client_flush(struct p9_client *c, struct p9_req_t *oldreq)
+{
+ struct p9_req_t *req;
+ int16_t oldtag;
+ int err;
+
+ err = p9_parse_header(oldreq->tc, NULL, NULL, &oldtag, 1);
+ if (err)
+ return err;
+
+ P9_DPRINTK(P9_DEBUG_9P, ">>> TFLUSH tag %d\n", oldtag);
+
+ req = p9_client_rpc(c, P9_TFLUSH, "w", oldtag);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+
+ req->flush_tag = oldtag;
+
+ /* we don't free anything here because RPC isn't complete */
+ return 0;
+}
+
+/**
* p9_client_rpc - issue a request and wait for a response
* @c: client session
- * @tc: &p9_fcall request to transmit
- * @rc: &p9_fcall to put reponse into
+ * @type: type of request
+ * @fmt: protocol format string (see protocol.c)
*
- * Returns 0 on success, error code on failure
+ * Returns request structure (which client must free using p9_free_req)
*/
-static int
-p9_client_rpc(struct p9_client *c, struct p9_fcall *tc, struct p9_fcall **rc)
+static struct p9_req_t *
+p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
{
- int tag, err, size;
- char *rdata;
+ va_list ap;
+ int tag, err;
struct p9_req_t *req;
unsigned long flags;
int sigpending;
int flushed = 0;
- P9_DPRINTK(P9_DEBUG_9P, "client %p tc %p rc %p\n", c, tc, rc);
+ P9_DPRINTK(P9_DEBUG_MUX, "client %p op %d\n", c, type);
if (c->status != Connected)
- return -EIO;
+ return ERR_PTR(-EIO);
if (signal_pending(current)) {
sigpending = 1;
@@ -395,50 +525,22 @@ p9_client_rpc(struct p9_client *c, struct p9_fcall *tc, struct p9_fcall **rc)
sigpending = 0;
tag = P9_NOTAG;
- if (tc->id != P9_TVERSION) {
+ if (type != P9_TVERSION) {
tag = p9_idpool_get(c->tagpool);
if (tag < 0)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
}
req = p9_tag_alloc(c, tag);
+ if (IS_ERR(req))
+ return req;
- /* if this is a flush request, backlink flush request now to
- * avoid race conditions later. */
- if (tc->id == P9_TFLUSH) {
- struct p9_req_t *other_req =
- p9_tag_lookup(c, tc->params.tflush.oldtag);
- if (other_req->status == REQ_STATUS_FLSH)
- other_req->flush_tag = tag;
- }
-
- p9_set_tag(tc, tag);
-
- /*
- * if client passed in a pre-allocated response fcall struct
- * then we just use that, otherwise we allocate one.
- */
-
- if (rc == NULL)
- req->rc = NULL;
- else
- req->rc = *rc;
- if (req->rc == NULL) {
- req->rc = kmalloc(sizeof(struct p9_fcall) + c->msize,
- GFP_KERNEL);
- if (!req->rc) {
- err = -ENOMEM;
- p9_idpool_put(tag, c->tagpool);
- p9_free_req(c, req);
- goto reterr;
- }
- *rc = req->rc;
- }
-
- rdata = (char *)req->rc+sizeof(struct p9_fcall);
-
- req->tc = tc;
- P9_DPRINTK(P9_DEBUG_9P, "request: tc: %p rc: %p\n", req->tc, req->rc);
+ /* marshall the data */
+ p9pdu_prepare(req->tc, tag, type);
+ va_start(ap, fmt);
+ err = p9pdu_vwritef(req->tc, c->dotu, fmt, ap);
+ va_end(ap);
+ p9pdu_finalize(req->tc);
err = c->trans_mod->request(c, req);
if (err < 0) {
@@ -447,28 +549,28 @@ p9_client_rpc(struct p9_client *c, struct p9_fcall *tc, struct p9_fcall **rc)
}
/* if it was a flush we just transmitted, return our tag */
- if (tc->id == P9_TFLUSH)
- return 0;
+ if (type == P9_TFLUSH)
+ return req;
again:
- P9_DPRINTK(P9_DEBUG_9P, "wait %p tag: %d\n", req->wq, tag);
+ P9_DPRINTK(P9_DEBUG_MUX, "wait %p tag: %d\n", req->wq, tag);
err = wait_event_interruptible(*req->wq,
req->status >= REQ_STATUS_RCVD);
- P9_DPRINTK(P9_DEBUG_9P, "wait %p tag: %d returned %d (flushed=%d)\n",
+ P9_DPRINTK(P9_DEBUG_MUX, "wait %p tag: %d returned %d (flushed=%d)\n",
req->wq, tag, err, flushed);
if (req->status == REQ_STATUS_ERROR) {
- P9_DPRINTK(P9_DEBUG_9P, "req_status error %d\n", req->t_err);
+ P9_DPRINTK(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err);
err = req->t_err;
} else if (err == -ERESTARTSYS && flushed) {
- P9_DPRINTK(P9_DEBUG_9P, "flushed - going again\n");
+ P9_DPRINTK(P9_DEBUG_MUX, "flushed - going again\n");
goto again;
} else if (req->status == REQ_STATUS_FLSHD) {
- P9_DPRINTK(P9_DEBUG_9P, "flushed - erestartsys\n");
+ P9_DPRINTK(P9_DEBUG_MUX, "flushed - erestartsys\n");
err = -ERESTARTSYS;
}
if ((err == -ERESTARTSYS) && (c->status == Connected) && (!flushed)) {
- P9_DPRINTK(P9_DEBUG_9P, "flushing\n");
+ P9_DPRINTK(P9_DEBUG_MUX, "flushing\n");
spin_lock_irqsave(&c->lock, flags);
if (req->status == REQ_STATUS_SENT)
req->status = REQ_STATUS_FLSH;
@@ -493,42 +595,17 @@ again:
if (err < 0)
goto reterr;
- size = le32_to_cpu(*(__le32 *) rdata);
-
- err = p9_deserialize_fcall(rdata, size, req->rc, c->dotu);
- if (err < 0) {
- P9_DPRINTK(P9_DEBUG_9P,
- "9p debug: client rpc deserialize returned %d\n", err);
- goto reterr;
+ err = p9_check_errors(c, req);
+ if (!err) {
+ P9_DPRINTK(P9_DEBUG_MUX, "exit: client %p op %d\n", c, type);
+ return req;
}
- if (req->rc->id == P9_RERROR) {
- int ecode = req->rc->params.rerror.errno;
- struct p9_str *ename = &req->rc->params.rerror.error;
-
- P9_DPRINTK(P9_DEBUG_MUX, "Rerror %.*s\n", ename->len,
- ename->str);
-
- if (c->dotu)
- err = -ecode;
-
- if (!err) {
- err = p9_errstr2errno(ename->str, ename->len);
-
- /* string match failed */
- if (!err) {
- PRINT_FCALL_ERROR("unknown error", req->rc);
- err = -ESERVERFAULT;
- }
- }
- } else
- err = 0;
-
reterr:
+ P9_DPRINTK(P9_DEBUG_MUX, "exit: client %p op %d error: %d\n", c, type,
+ err);
p9_free_req(c, req);
-
- P9_DPRINTK(P9_DEBUG_9P, "returning %d\n", err);
- return err;
+ return ERR_PTR(err);
}
static struct p9_fid *p9_fid_create(struct p9_client *clnt)
@@ -536,7 +613,7 @@ static struct p9_fid *p9_fid_create(struct p9_client *clnt)
int err;
struct p9_fid *fid;
- P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
+ P9_DPRINTK(P9_DEBUG_FID, "clnt %p\n", clnt);
fid = kmalloc(sizeof(struct p9_fid), GFP_KERNEL);
if (!fid)
return ERR_PTR(-ENOMEM);
@@ -569,7 +646,7 @@ static void p9_fid_destroy(struct p9_fid *fid)
{
struct p9_client *clnt;
- P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
+ P9_DPRINTK(P9_DEBUG_FID, "fid %d\n", fid->fid);
clnt = fid->clnt;
p9_idpool_put(fid->fid, clnt->fidpool);
spin_lock(&clnt->lock);
@@ -578,49 +655,46 @@ static void p9_fid_destroy(struct p9_fid *fid)
kfree(fid);
}
-static int p9_client_version(struct p9_client *clnt)
+int p9_client_version(struct p9_client *c)
{
int err = 0;
- struct p9_fcall *tc, *rc;
- struct p9_str *version;
+ struct p9_req_t *req;
+ char *version;
+ int msize;
- P9_DPRINTK(P9_DEBUG_9P, "%p\n", clnt);
- err = 0;
- tc = NULL;
- rc = NULL;
-
- tc = p9_create_tversion(clnt->msize,
- clnt->dotu ? "9P2000.u" : "9P2000");
- if (IS_ERR(tc)) {
- err = PTR_ERR(tc);
- tc = NULL;
- goto error;
- }
+ P9_DPRINTK(P9_DEBUG_9P, ">>> TVERSION msize %d extended %d\n",
+ c->msize, c->dotu);
+ req = p9_client_rpc(c, P9_TVERSION, "ds", c->msize,
+ c->dotu ? "9P2000.u" : "9P2000");
+ if (IS_ERR(req))
+ return PTR_ERR(req);
- err = p9_client_rpc(clnt, tc, &rc);
- if (err)
+ err = p9pdu_readf(req->rc, c->dotu, "ds", &msize, &version);
+ if (err) {
+ P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err);
goto error;
+ }
- version = &rc->params.rversion.version;
- if (version->len == 8 && !memcmp(version->str, "9P2000.u", 8))
- clnt->dotu = 1;
- else if (version->len == 6 && !memcmp(version->str, "9P2000", 6))
- clnt->dotu = 0;
+ P9_DPRINTK(P9_DEBUG_9P, "<<< RVERSION msize %d %s\n", msize, version);
+ if (!memcmp(version, "9P2000.u", 8))
+ c->dotu = 1;
+ else if (!memcmp(version, "9P2000", 6))
+ c->dotu = 0;
else {
err = -EREMOTEIO;
goto error;
}
- if (rc->params.rversion.msize < clnt->msize)
- clnt->msize = rc->params.rversion.msize;
+ if (msize < c->msize)
+ c->msize = msize;
error:
- kfree(tc);
- kfree(rc);
+ kfree(version);
+ p9_free_req(c, req);
return err;
}
-EXPORT_SYMBOL(p9_client_auth);
+EXPORT_SYMBOL(p9_client_version);
struct p9_client *p9_client_create(const char *dev_name, char *options)
{
@@ -656,7 +730,7 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
goto error;
}
- P9_DPRINTK(P9_DEBUG_9P, "clnt %p trans %p msize %d dotu %d\n",
+ P9_DPRINTK(P9_DEBUG_MUX, "clnt %p trans %p msize %d dotu %d\n",
clnt, clnt->trans_mod, clnt->msize, clnt->dotu);
err = clnt->trans_mod->create(clnt, dev_name, options);
@@ -682,7 +756,7 @@ void p9_client_destroy(struct p9_client *clnt)
{
struct p9_fid *fid, *fidptr;
- P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
+ P9_DPRINTK(P9_DEBUG_MUX, "clnt %p\n", clnt);
if (clnt->trans_mod)
clnt->trans_mod->close(clnt);
@@ -712,14 +786,13 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
char *uname, u32 n_uname, char *aname)
{
int err;
- struct p9_fcall *tc, *rc;
+ struct p9_req_t *req;
struct p9_fid *fid;
+ struct p9_qid qid;
- P9_DPRINTK(P9_DEBUG_9P, "clnt %p afid %d uname %s aname %s\n",
- clnt, afid?afid->fid:-1, uname, aname);
+ P9_DPRINTK(P9_DEBUG_9P, ">>> TATTACH afid %d uname %s aname %s\n",
+ afid ? afid->fid : -1, uname, aname);
err = 0;
- tc = NULL;
- rc = NULL;
fid = p9_fid_create(clnt);
if (IS_ERR(fid)) {
@@ -728,73 +801,75 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
goto error;
}
- tc = p9_create_tattach(fid->fid, afid?afid->fid:P9_NOFID, uname, aname,
- n_uname, clnt->dotu);
- if (IS_ERR(tc)) {
- err = PTR_ERR(tc);
- tc = NULL;
+ req = p9_client_rpc(clnt, P9_TATTACH, "ddss?d", fid->fid,
+ afid ? afid->fid : P9_NOFID, uname, aname, n_uname);
+ if (IS_ERR(req)) {
+ err = PTR_ERR(req);
goto error;
}
- err = p9_client_rpc(clnt, tc, &rc);
- if (err)
+ err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid);
+ if (err) {
+ p9_free_req(clnt, req);
goto error;
+ }
- memmove(&fid->qid, &rc->params.rattach.qid, sizeof(struct p9_qid));
- kfree(tc);
- kfree(rc);
+ P9_DPRINTK(P9_DEBUG_9P, "<<< RATTACH qid %x.%llx.%x\n",
+ qid.type, qid.path, qid.version);
+
+ memmove(&fid->qid, &qid, sizeof(struct p9_qid));
+
+ p9_free_req(clnt, req);
return fid;
error:
- kfree(tc);
- kfree(rc);
if (fid)
p9_fid_destroy(fid);
return ERR_PTR(err);
}
EXPORT_SYMBOL(p9_client_attach);
-struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname,
- u32 n_uname, char *aname)
+struct p9_fid *
+p9_client_auth(struct p9_client *clnt, char *uname, u32 n_uname, char *aname)
{
int err;
- struct p9_fcall *tc, *rc;
- struct p9_fid *fid;
+ struct p9_req_t *req;
+ struct p9_qid qid;
+ struct p9_fid *afid;
- P9_DPRINTK(P9_DEBUG_9P, "clnt %p uname %s aname %s\n", clnt, uname,
- aname);
+ P9_DPRINTK(P9_DEBUG_9P, ">>> TAUTH uname %s aname %s\n", uname, aname);
err = 0;
- tc = NULL;
- rc = NULL;
- fid = p9_fid_create(clnt);
- if (IS_ERR(fid)) {
- err = PTR_ERR(fid);
- fid = NULL;
+ afid = p9_fid_create(clnt);
+ if (IS_ERR(afid)) {
+ err = PTR_ERR(afid);
+ afid = NULL;
goto error;
}
- tc = p9_create_tauth(fid->fid, uname, aname, n_uname, clnt->dotu);
- if (IS_ERR(tc)) {
- err = PTR_ERR(tc);
- tc = NULL;
+ req = p9_client_rpc(clnt, P9_TAUTH, "dss?d",
+ afid ? afid->fid : P9_NOFID, uname, aname, n_uname);
+ if (IS_ERR(req)) {
+ err = PTR_ERR(req);
goto error;
}
- err = p9_client_rpc(clnt, tc, &rc);
- if (err)
+ err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid);
+ if (err) {
+ p9_free_req(clnt, req);
goto error;
+ }
- memmove(&fid->qid, &rc->params.rauth.qid, sizeof(struct p9_qid));
- kfree(tc);
- kfree(rc);
- return fid;
+ P9_DPRINTK(P9_DEBUG_9P, "<<< RAUTH qid %x.%llx.%x\n",
+ qid.type, qid.path, qid.version);
+
+ memmove(&afid->qid, &qid, sizeof(struct p9_qid));
+ p9_free_req(clnt, req);
+ return afid;
error:
- kfree(tc);
- kfree(rc);
- if (fid)
- p9_fid_destroy(fid);
+ if (afid)
+ p9_fid_destroy(afid);
return ERR_PTR(err);
}
EXPORT_SYMBOL(p9_clie