diff options
-rw-r--r-- | fs/9p/v9fs_vfs.h | 4 | ||||
-rw-r--r-- | fs/9p/vfs_dir.c | 4 | ||||
-rw-r--r-- | fs/9p/vfs_file.c | 2 | ||||
-rw-r--r-- | fs/9p/vfs_inode.c | 38 | ||||
-rw-r--r-- | fs/9p/vfs_super.c | 6 | ||||
-rw-r--r-- | include/net/9p/9p.h | 7 | ||||
-rw-r--r-- | include/net/9p/client.h | 7 | ||||
-rw-r--r-- | net/9p/client.c | 931 | ||||
-rw-r--r-- | net/9p/protocol.c | 85 | ||||
-rw-r--r-- | net/9p/protocol.h | 5 | ||||
-rw-r--r-- | net/9p/trans_fd.c | 62 | ||||
-rw-r--r-- | net/9p/util.c | 4 |
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_client_auth); @@ -803,15 +878,13 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames, int clone) { int err; - struct p9_fcall *tc, *rc; struct p9_client *clnt; struct p9_fid *fid; + struct p9_qid *wqids; + struct p9_req_t *req; + int16_t nwqids, count; - P9_DPRINTK(P9_DEBUG_9P, "fid %d nwname %d wname[0] %s\n", - oldfid->fid, nwname, wnames?wnames[0]:NULL); err = 0; - tc = NULL; - rc = NULL; clnt = oldfid->clnt; if (clone) { fid = p9_fid_create(clnt); @@ -825,53 +898,46 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames, } else fid = oldfid; - tc = p9_create_twalk(oldfid->fid, fid->fid, nwname, wnames); - if (IS_ERR(tc)) { - err = PTR_ERR(tc); - tc = NULL; + + P9_DPRINTK(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %d wname[0] %s\n", + oldfid->fid, fid->fid, nwname, wnames ? wnames[0] : NULL); + + req = p9_client_rpc(clnt, P9_TWALK, "ddT", oldfid->fid, fid->fid, + nwname, wnames); + if (IS_ERR(req)) { + err = PTR_ERR(req); goto error; } - err = p9_client_rpc(clnt, tc, &rc); - if (err) { - if (rc && rc->id == P9_RWALK) - goto clunk_fid; - else - goto error; - } + err = p9pdu_readf(req->rc, clnt->dotu, "R", &nwqids, &wqids); + p9_free_req(clnt, req); + if (err) + goto clunk_fid; - if (rc->params.rwalk.nwqid != nwname) { + P9_DPRINTK(P9_DEBUG_9P, "<<< RWALK nwqid %d:\n", nwqids); + + if (nwqids != nwname) { err = -ENOENT; goto clunk_fid; } + for (count = 0; count < nwqids; count++) + P9_DPRINTK(P9_DEBUG_9P, "<<< [%d] %x.%llx.%x\n", + count, wqids[count].type, wqids[count].path, + wqids[count].version); + if (nwname) - memmove(&fid->qid, - &rc->params.rwalk.wqids[rc->params.rwalk.nwqid - 1], - sizeof(struct p9_qid)); + memmove(&fid->qid, &wqids[nwqids - 1], sizeof(struct p9_qid)); else fid->qid = oldfid->qid; - kfree(tc); - kfree(rc); return fid; clunk_fid: - kfree(tc); - kfree(rc); - rc = NULL; - tc = p9_create_tclunk(fid->fid); - if (IS_ERR(tc)) { - err = PTR_ERR(tc); - tc = NULL; - goto error; - } - - p9_client_rpc(clnt, tc, &rc); + p9_client_clunk(fid); + fid = NULL; error: - kfree(tc); - kfree(rc); if (fid && (fid != oldfid)) p9_fid_destroy(fid); @@ -882,35 +948,36 @@ EXPORT_SYMBOL(p9_client_walk); int p9_client_open(struct p9_fid *fid, int mode) { int err; - struct p9_fcall *tc, *rc; struct p9_client *clnt; + struct p9_req_t *req; + struct p9_qid qid; + int iounit; - P9_DPRINTK(P9_DEBUG_9P, "fid %d mode %d\n", fid->fid, mode); + P9_DPRINTK(P9_DEBUG_9P, ">>> TOPEN fid %d mode %d\n", fid->fid, mode); err = 0; - tc = NULL; - rc = NULL; clnt = fid->clnt; if (fid->mode != -1) return -EINVAL; - tc = p9_create_topen(fid->fid, mode); - if (IS_ERR(tc)) { - err = PTR_ERR(tc); - tc = NULL; - goto done; + req = p9_client_rpc(clnt, P9_TOPEN, "db", fid->fid, mode); + if (IS_ERR(req)) { + err = PTR_ERR(req); + goto error; } - err = p9_client_rpc(clnt, tc, &rc); + err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit); + p9_free_req(clnt, req); if (err) - goto done; + goto error; + + P9_DPRINTK(P9_DEBUG_9P, "<<< ROPEN qid %x.%llx.%x iounit %x\n", + qid.type, qid.path, qid.version, iounit); fid->mode = mode; - fid->iounit = rc->params.ropen.iounit; + fid->iounit = iounit; -done: - kfree(tc); - kfree(rc); +error: return err; } EXPORT_SYMBOL(p9_client_open); @@ -919,37 +986,38 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode, char *extension) { int err; - struct p9_fcall *tc, *rc; struct p9_client *clnt; + struct p9_req_t *req; + struct p9_qid qid; + int iounit; - P9_DPRINTK(P9_DEBUG_9P, "fid %d name %s perm %d mode %d\n", fid->fid, - name, perm, mode); + P9_DPRINTK(P9_DEBUG_9P, ">>> TCREATE fid %d name %s perm %d mode %d\n", + fid->fid, name, perm, mode); err = 0; - tc = NULL; - rc = NULL; clnt = fid->clnt; if (fid->mode != -1) return -EINVAL; - tc = p9_create_tcreate(fid->fid, name, perm, mode, extension, - clnt->dotu); - if (IS_ERR(tc)) { - err = PTR_ERR(tc); - tc = NULL; - goto done; + req = p9_client_rpc(clnt, P9_TCREATE, "dsdb?s", fid->fid, name, perm, + mode, extension); + if (IS_ERR(req)) { + err = PTR_ERR(req); + goto error; } - err = p9_client_rpc(clnt, tc, &rc); + err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit); + p9_free_req(clnt, req); if (err) - goto done; + goto error; + + P9_DPRINTK(P9_DEBUG_9P, "<<< RCREATE qid %x.%llx.%x iounit %x\n", + qid.type, qid.path, qid.version, iounit); fid->mode = mode; - fid->iounit = rc->params.ropen.iounit; + fid->iounit = iounit; -done: - kfree(tc); - kfree(rc); +error: return err; } EXPORT_SYMBOL(p9_client_fcreate); @@ -957,31 +1025,25 @@ EXPORT_SYMBOL(p9_client_fcreate); int p9_client_clunk(struct p9_fid *fid) { int err; - struct p9_fcall *tc, *rc; struct p9_client *clnt; + struct p9_req_t *req; - P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); + P9_DPRINTK(P9_DEBUG_9P, ">>> TCLUNK fid %d\n", fid->fid); err = 0; - tc = NULL; - rc = NULL; clnt = fid->clnt; - tc = p9_create_tclunk(fid->fid); - if (IS_ERR(tc)) { - err = PTR_ERR(tc); - tc = NULL; - goto done; + req = p9_client_rpc(clnt, P9_TCLUNK, "d", fid->fid); + if (IS_ERR(req)) { + err = PTR_ERR(req); + goto error; } - err = p9_client_rpc(clnt, tc, &rc); - if (err) - goto done; + P9_DPRINTK(P9_DEBUG_9P, "<<< RCLUNK fid %d\n", fid->fid); + p9_free_req(clnt, req); p9_fid_destroy(fid); -done: - kfree(tc); - kfree(rc); +error: return err; } EXPORT_SYMBOL(p9_client_clunk); @@ -989,31 +1051,25 @@ EXPORT_SYMBOL(p9_client_clunk); int p9_client_remove(struct p9_fid *fid) { int err; - struct p9_fcall *tc, *rc; struct p9_client *clnt; + struct p9_req_t *req; - P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); + P9_DPRINTK(P9_DEBUG_9P, ">>> TREMOVE fid %d\n", fid->fid); err = 0; - tc = NULL; - rc = NULL; clnt = fid->clnt; - tc = p9_create_tremove(fid->fid); - if (IS_ERR(tc)) { - err = PTR_ERR(tc); - tc = NULL; - goto done; + req = p9_client_rpc(clnt, P9_TREMOVE, "d", fid->fid); + if (IS_ERR(req)) { + err = PTR_ERR(req); + goto error; } - err = p9_client_rpc(clnt, tc, &rc); - if (err) - goto done; + P9_DPRINTK(P9_DEBUG_9P, "<<< RREMOVE fid %d\n", fid->fid); + p9_free_req(clnt, req); p9_fid_destroy(fid); -done: - kfree(tc); - kfree(rc); +error: return err; } EXPORT_SYMBOL(p9_client_remove); @@ -1022,15 +1078,14 @@ int p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, u32 count) { - int err, n, rsize, total; - struct p9_fcall *tc, *rc; + int err, rsize, total; struct p9_client *clnt; + struct p9_req_t *req; + char *dataptr; - P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu %d\n", fid->fid, + P9_DPRINTK(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n", fid->fid, (long long unsigned) offset, count); err = 0; - tc = NULL; - rc = NULL; clnt = fid->clnt; total = 0; @@ -1038,53 +1093,40 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) rsize = clnt->msize - P9_IOHDRSZ; - do { - if (count < rsize) - rsize = count; + if (count < rsize) + rsize = count; - tc = p9_create_tread(fid->fid, offset, rsize); - if (IS_ERR(tc)) { - err = PTR_ERR(tc); - tc = NULL; - goto error; - } + req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, rsize); + if (IS_ERR(req)) { + err = PTR_ERR(req); + goto error; + } - err = p9_client_rpc(clnt, tc, &rc); - if (err) - goto error; + err = p9pdu_readf(req->rc, clnt->dotu, "D", &count, &dataptr); + if (err) + goto free_and_error; - n = rc->params.rread.count; - if (n > count) - n = count; + P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count); - if (data) { - memmove(data, rc->params.rread.data, n); - data += n; - } + if (data) { + memmove(data, dataptr, count); + data += count; + } - if (udata) { - err = copy_to_user(udata, rc->params.rread.data, n); - if (err) { - err = -EFAULT; - goto error; - } - udata += n; + if (udata) { + err = copy_to_user(udata, dataptr, count); + if (err) { + err = -EFAULT; + goto free_and_error; } + } - count -= n; - offset += n; - total += n; - kfree(tc); - tc = NULL; - kfree(rc); - rc = NULL; - } while (count > 0 && n == rsize); - - return total; + p9_free_req(clnt, req); + return count; +free_and_error: + p9_free_req(clnt, req); error: - kfree(tc); - kfree(rc); return err; } EXPORT_SYMBOL(p9_client_read); @@ -1093,15 +1135,13 @@ int p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, u64 offset, u32 count) { - int err, n, rsize, total; - struct p9_fcall *tc, *rc; + int err, rsize, total; struct p9_client *clnt; + struct p9_req_t *req; - P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid, - (long long unsigned) offset, count); + P9_DPRINTK(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %d\n", + fid->fid, (long long unsigned) offset, count); err = 0; - tc = NULL; - rc = NULL; clnt = fid->clnt; total = 0; @@ -1109,129 +1149,70 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) rsize = clnt->msize - P9_IOHDRSZ; - do { - if (count < rsize) - rsize = count; - - if (data) - tc = p9_create_twrite(fid->fid, offset, rsize, data); - else - tc = p9_create_twrite_u(fid->fid, offset, rsize, udata); - if (IS_ERR(tc)) { - err = PTR_ERR(tc); - tc = NULL; - goto error; - } - - err = p9_client_rpc(clnt, tc, &rc); - if (err) - goto error; - - n = rc->params.rread.count; - count -= n; - - if (data) - data += n; - else - udata += n; + if (count < rsize) + rsize = count; + if (data) + req = p9_client_rpc(clnt, P9_TWRITE, "dqD", fid->fid, offset, + rsize, data); + else + req = p9_client_rpc(clnt, P9_TWRITE, "dqU", fid->fid, offset, + rsize, udata); + if (IS_ERR(req)) { + err = PTR_ERR(req); + goto error; + } - offset += n; - total += n; - kfree(tc); - tc = NULL; - kfree(rc); - rc = NULL; - } while (count > 0); + err = p9pdu_readf(req->rc, clnt->dotu, "d", &count); + if (err) + goto free_and_error; + P9_DPRINTK(P9_DEBUG_9P, "<<< RWRITE count %d\n", count); - return total; + p9_free_req(clnt, req); + return count; +free_and_error: + p9_free_req(clnt, req); error: - kfree(tc); - kfree(rc); return err; } EXPORT_SYMBOL(p9_client_write); -static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu) +struct p9_wstat *p9_client_stat(struct p9_fid *fid) { - int n; - char *p; - struct p9_stat *ret; - - n = sizeof(struct p9_stat) + st->name.len + st->uid.len + st->gid.len + - st->muid.len; + int err; + struct p9_client *clnt; + struct p9_wstat *ret = kmalloc(sizeof(struct p9_wstat), GFP_KERNEL); + struct p9_req_t *req; + u16 ignored; - if (dotu) - n += st->extension.len; + P9_DPRINTK(P9_DEBUG_9P, ">>> TSTAT fid %d\n", fid->fid); - ret = kmalloc(n, GFP_KERNEL); if (!ret) return ERR_PTR(-ENOMEM); - memmove(ret, st, sizeof(struct p9_stat)); - p = ((char *) ret) + sizeof(struct p9_stat); - memmove(p, st->name.str, st->name.len); - ret->name.str = p; - p += st->name.len; - memmove(p, st->uid.str, st->uid.len); - ret->uid.str = p; - p += st->uid.len; - memmove(p, st->gid.str, st->gid.len); - ret->gid.str = p; - p += st->gid.len; - memmove(p, st->muid.str, st->muid.len); - ret->muid.str = p; - p += st->muid.len; - - if (dotu) { - memmove(p, st->extension.str, st->extension.len); - ret->extension.str = p; - p += st->extension.len; - } - - return ret; -} - -struct p9_stat *p9_client_stat(struct p9_fid *fid) -{ - int err; - struct p9_fcall *tc, *rc; - struct p9_client *clnt; - struct p9_stat *ret; - - P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); err = 0; - tc = NULL; - rc = NULL; - ret = NULL; clnt = fid->clnt; - tc = p9_create_tstat(fid->fid); - if (IS_ERR(tc)) { - err = PTR_ERR(tc); - tc = NULL; + req = p9_client_rpc(clnt, P9_TSTAT, "d", fid->fid); + if (IS_ERR(req)) { + err = PTR_ERR(req); goto error; } - err = p9_client_rpc(clnt, tc, &rc); + err = p9pdu_readf(req->rc, clnt->dotu, "wS", &ignored, ret); + p9_free_req(clnt, req); if (err) goto error; - ret = p9_clone_stat(&rc->params.rstat.stat, clnt->dotu); - if (IS_ERR(ret)) { - err = PTR_ERR(ret); - ret = NULL; - goto error; - } + P9_DPRINTK(P9_DEBUG_9P, + "<<< RSTAT sz=%x type=%x dev=%x qid=%2.2x %4.4x %8.8llx" + " mode=%8.8x uid=%d gid=%d size=%lld %s\n", + ret->size, ret->type, ret->dev, ret->qid.type, + ret->qid.version, ret->qid.path, ret->mode, + ret->n_uid, ret->n_gid, ret->length, ret->name); - kfree(tc); - kfree(rc); return ret; - error: - kfree(tc); - kfree(rc); - kfree(ret); return ERR_PTR(err); } EXPORT_SYMBOL(p9_client_stat); @@ -1239,27 +1220,23 @@ EXPORT_SYMBOL(p9_client_stat); int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst) { int err; - struct p9_fcall *tc, *rc; + struct p9_req_t *req; struct p9_client *clnt; - P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid); + P9_DPRINTK(P9_DEBUG_9P, ">>> TWSTAT fid %d\n", fid->fid); err = 0; - tc = NULL; - rc = NULL; clnt = fid->clnt; - tc = p9_create_twstat(fid->fid, wst, clnt->dotu); - if (IS_ERR(tc)) { - err = PTR_ERR(tc); - tc = NULL; - goto done; + req = p9_client_rpc(clnt, P9_TWSTAT, "dwS", fid->fid, 0, wst); + if (IS_ERR(req)) { + err = PTR_ERR(req); + goto error; } - err = p9_client_rpc(clnt, tc, &rc); + P9_DPRINTK(P9_DEBUG_9P, "<<< RWSTAT fid %d\n", fid->fid); -done: - kfree(tc); - kfree(rc); + p9_free_req(clnt, req); +error: return err; } EXPORT_SYMBOL(p9_client_wstat); diff --git a/net/9p/protocol.c b/net/9p/protocol.c index 43e98220e9a4..4ebeffd21d3d 100644 --- a/net/9p/protocol.c +++ b/net/9p/protocol.c @@ -27,6 +27,7 @@ #include <linux/module.h> #include <linux/errno.h> +#include <linux/uaccess.h> #include <net/9p/9p.h> #include <net/9p/client.h> #include "protocol.h" @@ -51,6 +52,38 @@ static int p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...); +#define PACKET_DEBUG 0 + +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) + printk(KERN_NOTICE "[[(%d)[ %s\n", datalen, buf); + else + printk(KERN_NOTICE "]](%d)] %s\n", datalen, buf); +} +EXPORT_SYMBOL(p9pdu_dump); + void p9stat_free(struct p9_wstat *stbuf) { kfree(stbuf->name); @@ -77,6 +110,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 @@ -174,7 +219,6 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) stbuf->extension = NULL; stbuf->n_uid = stbuf->n_gid = stbuf->n_muid = -1; - errcode = p9pdu_readf(pdu, optional, "wwdQdddqssss?sddd", @@ -332,7 +376,6 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) case 's':{ const char *ptr = va_arg(ap, const char *); int16_t len = 0; - if (ptr) len = MIN(strlen(ptr), USHORT_MAX); @@ -356,7 +399,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 +417,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 *); + 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 +508,29 @@ p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...) return ret; } + +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; + + if (PACKET_DEBUG) + p9pdu_dump(0, pdu); + + return err; +} + +void p9pdu_reset(struct p9_fcall *pdu) +{ + pdu->offset = 0; + pdu->size = 0; +} diff --git a/net/9p/protocol.h b/net/9p/protocol.h index 596ee10d506f..ccde462e7ac5 100644 --- a/net/9p/protocol.h +++ b/net/9p/protocol.h @@ -27,5 +27,8 @@ int p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap); - int p9pdu_readf(struct p9_fcall *pdu, int optional, const char *fmt, ...); +int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type); +int p9pdu_finalize(struct p9_fcall *pdu); +void p9pdu_dump(int, struct p9_fcall *); +void p9pdu_reset(struct p9_fcall *pdu); diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index e147ec539585..e8ebe2cb7e8b 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -181,7 +181,7 @@ static void p9_mux_poll_stop(struct p9_conn *m) * */ -void p9_conn_cancel(struct p9_conn *m, int err) +static void p9_conn_cancel(struct p9_conn *m, int err) { struct p9_req_t *req, *rtmp; unsigned long flags; @@ -287,7 +287,7 @@ static void p9_read_work(struct work_struct *work) if (m->err < 0) return; - P9_DPRINTK(P9_DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos); + P9_DPRINTK(P9_DEBUG_TRANS, "start mux %p pos %d\n", m, m->rpos); if (!m->rbuf) { m->rbuf = m->tmp_buf; @@ -296,11 +296,11 @@ static void p9_read_work(struct work_struct *work) } clear_bit(Rpending, &m->wsched); - P9_DPRINTK(P9_DEBUG_MUX, "read mux %p pos %d size: %d = %d\n", m, + P9_DPRINTK(P9_DEBUG_TRANS, "read mux %p pos %d size: %d = %d\n", m, m->rpos, m->rsize, m->rsize-m->rpos); err = p9_fd_read(m->client, m->rbuf + m->rpos, m->rsize - m->rpos); - P9_DPRINTK(P9_DEBUG_MUX, "mux %p got %d bytes\n", m, err); + P9_DPRINTK(P9_DEBUG_TRANS, "mux %p got %d bytes\n", m, err); if (err == -EAGAIN) { clear_bit(Rworksched, &m->wsched); return; @@ -313,7 +313,7 @@ static void p9_read_work(struct work_struct *work) if ((!m->req) && (m->rpos == m->rsize)) { /* header read in */ u16 tag; - P9_DPRINTK(P9_DEBUG_MUX, "got new header\n"); + P9_DPRINTK(P9_DEBUG_TRANS, "got new header\n"); n = le32_to_cpu(*(__le32 *) m->rbuf); /* read packet size */ if (n >= m->client->msize) { @@ -324,8 +324,8 @@ static void p9_read_work(struct work_struct *work) } tag = le16_to_cpu(*(__le16 *) (m->rbuf+5)); /* read tag */ - P9_DPRINTK(P9_DEBUG_MUX, "mux %p pkt: size: %d bytes tag: %d\n", - m, n, tag); + P9_DPRINTK(P9_DEBUG_TRANS, + "mux %p pkt: size: %d bytes tag: %d\n", m, n, tag); m->req = p9_tag_lookup(m->client, tag); if (!m->req) { @@ -351,7 +351,7 @@ static void p9_read_work(struct work_struct *work) /* not an else because some packets (like clunk) have no payload */ if ((m->req) && (m->rpos == m->rsize)) { /* packet is read in */ - P9_DPRINTK(P9_DEBUG_MUX, "got new packet\n"); + P9_DPRINTK(P9_DEBUG_TRANS, "got new packet\n"); list_del(&m->req->req_list); p9_client_cb(m->client, m->req); @@ -369,7 +369,7 @@ static void p9_read_work(struct work_struct *work) n = p9_fd_poll(m->client, NULL); if (n & POLLIN) { - P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m); + P9_DPRINTK(P9_DEBUG_TRANS, "sched read work %p\n", m); queue_work(p9_mux_wq, &m->rq); } else clear_bit(Rworksched, &m->wsched); @@ -453,11 +453,11 @@ static void p9_write_work(struct work_struct *work) spin_unlock(&m->client->lock); } - P9_DPRINTK(P9_DEBUG_MUX, "mux %p pos %d size %d\n", m, m->wpos, + P9_DPRINTK(P9_DEBUG_TRANS, "mux %p pos %d size %d\n", m, m->wpos, m->wsize); clear_bit(Wpending, &m->wsched); err = p9_fd_write(m->client, m->wbuf + m->wpos, m->wsize - m->wpos); - P9_DPRINTK(P9_DEBUG_MUX, "mux %p sent %d bytes\n", m, err); + P9_DPRINTK(P9_DEBUG_TRANS, "mux %p sent %d bytes\n", m, err); if (err == -EAGAIN) { clear_bit(Wworksched, &m->wsched); return; @@ -481,7 +481,7 @@ static void p9_write_work(struct work_struct *work) n = p9_fd_poll(m->client, NULL); if (n & POLLOUT) { - P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m); + P9_DPRINTK(P9_DEBUG_TRANS, "sched write work %p\n", m); queue_work(p9_mux_wq, &m->wq); } else clear_bit(Wworksched, &m->wsched); @@ -558,7 +558,8 @@ static struct p9_conn *p9_conn_create(struct p9_client *client) int n; struct p9_conn *m; - P9_DPRINTK(P9_DEBUG_MUX, "client %p msize %d\n", client, client->msize); + P9_DPRINTK(P9_DEBUG_TRANS, "client %p msize %d\n", client, + client->msize); m = kzalloc(sizeof(struct p9_conn), GFP_KERNEL); if (!m) return ERR_PTR(-ENOMEM); @@ -575,12 +576,12 @@ static struct p9_conn *p9_conn_create(struct p9_client *client) n = p9_fd_poll(client, &m->pt); if (n & POLLIN) { - P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m); + P9_DPRINTK(P9_DEBUG_TRANS, "mux %p can read\n", m); set_bit(Rpending, &m->wsched); } if (n & POLLOUT) { - P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m); + P9_DPRINTK(P9_DEBUG_TRANS, "mux %p can write\n", m); set_bit(Wpending, &m->wsched); } @@ -602,7 +603,7 @@ static void p9_poll_mux(struct p9_conn *m) n = p9_fd_poll(m->client, NULL); if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) { - P9_DPRINTK(P9_DEBUG_MUX, "error mux %p err %d\n", m, n); + P9_DPRINTK(P9_DEBUG_TRANS, "error mux %p err %d\n", m, n); if (n >= 0) n = -ECONNRESET; p9_conn_cancel(m, n); @@ -610,19 +611,19 @@ static void p9_poll_mux(struct p9_conn *m) if (n & POLLIN) { set_bit(Rpending, &m->wsched); - P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m); + P9_DPRINTK(P9_DEBUG_TRANS, "mux %p can read\n", m); if (!test_and_set_bit(Rworksched, &m->wsched)) { - P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m); + P9_DPRINTK(P9_DEBUG_TRANS, "sched read work %p\n", m); queue_work(p9_mux_wq, &m->rq); } } if (n & POLLOUT) { set_bit(Wpending, &m->wsched); - P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m); + P9_DPRINTK(P9_DEBUG_TRANS, "mux %p can write\n", m); if ((m->wsize || !list_empty(&m->unsent_req_list)) && !test_and_set_bit(Wworksched, &m->wsched)) { - P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m); + P9_DPRINTK(P9_DEBUG_TRANS, "sched write work %p\n", m); queue_work(p9_mux_wq, &m->wq); } } @@ -645,8 +646,8 @@ static int p9_fd_request(struct p9_client *client, struct p9_req_t *req) struct p9_trans_fd *ts = client->trans; struct p9_conn *m = ts->conn; - P9_DPRINTK(P9_DEBUG_MUX, "mux %p task %p tcall %p id %d\n", m, current, - req->tc, req->tc->id); + P9_DPRINTK(P9_DEBUG_TRANS, "mux %p task %p tcall %p id %d\n", m, + current, req->tc, req->tc->id); if (m->err < 0) return m->err; @@ -672,19 +673,12 @@ static int p9_fd_cancel(struct p9_client *client, struct p9_req_t *req) struct p9_trans_fd *ts = client->trans; struct p9_conn *m = ts->conn; - P9_DPRINTK(P9_DEBUG_MUX, "mux %p req %p\n", m, req); + P9_DPRINTK(P9_DEBUG_TRANS, "mux %p req %p\n", m, req); spin_lock(&client->lock); list_del(&req->req_list); spin_unlock(&client->lock); - /* if a response was received for a request, do nothing */ - if (req->rc || req->t_err) { - P9_DPRINTK(P9_DEBUG_MUX, - "mux %p req %p response already received\n", m, req); - return 0; - } - if (req->status == REQ_STATUS_UNSENT) { req->status = REQ_STATUS_FLSHD; return 0; @@ -809,7 +803,7 @@ static int p9_socket_open(struct p9_client *client, struct socket *csocket) static void p9_conn_destroy(struct p9_conn *m) { - P9_DPRINTK(P9_DEBUG_MUX, "mux %p prev %p next %p\n", m, + P9_DPRINTK(P9_DEBUG_TRANS, "mux %p prev %p next %p\n", m, m->mux_list.prev, m->mux_list.next); p9_mux_poll_stop(m); @@ -1060,7 +1054,7 @@ static int p9_poll_proc(void *a) { unsigned long flags; - P9_DPRINTK(P9_DEBUG_MUX, "start %p\n", current); + P9_DPRINTK(P9_DEBUG_TRANS, "start %p\n", current); repeat: spin_lock_irqsave(&p9_poll_lock, flags); while (!list_empty(&p9_poll_pending_list)) { @@ -1078,7 +1072,7 @@ static int p9_poll_proc(void *a) set_current_state(TASK_INTERRUPTIBLE); if (list_empty(&p9_poll_pending_list)) { - P9_DPRINTK(P9_DEBUG_MUX, "sleeping...\n"); + P9_DPRINTK(P9_DEBUG_TRANS, "sleeping...\n"); schedule(); } __set_current_state(TASK_RUNNING); @@ -1086,7 +1080,7 @@ static int p9_poll_proc(void *a) if (!kthread_should_stop()) goto repeat; - P9_DPRINTK(P9_DEBUG_MUX, "finish\n"); + P9_DPRINTK(P9_DEBUG_TRANS, "finish\n"); return 0; } diff --git a/net/9p/util.c b/net/9p/util.c index 958fc58cd1ff..dc4ec05ad93d 100644 --- a/net/9p/util.c +++ b/net/9p/util.c @@ -105,6 +105,7 @@ retry: else if (error) return -1; + P9_DPRINTK(P9_DEBUG_MUX, " id %d pool %p\n", i, p); return i; } EXPORT_SYMBOL(p9_idpool_get); @@ -121,6 +122,9 @@ EXPORT_SYMBOL(p9_idpool_get); void p9_idpool_put(int id, struct p9_idpool *p) { unsigned long flags; + + P9_DPRINTK(P9_DEBUG_MUX, " id %d pool %p\n", id, p); + spin_lock_irqsave(&p->lock, flags); idr_remove(&p->pool, id); spin_unlock_irqrestore(&p->lock, flags); |