forked from Minki/linux
Pull request for inclusion in 4.20
* Finish removing the custom 9p request cache mechanism * Embed part of the fcall in the request to have better slab performance (msize usually is power of two aligned) * syzkaller fixes: - add a refcount to 9p requests to avoid use after free - a few double free issues * A few coverity fixes * Some old patches that were in the bugzilla: - do not trust pdu content for size header - mount option for lock retry interval ---------------------------------------------------------------- Dan Carpenter (1): 9p: potential NULL dereference Dinu-Razvan Chis-Serban (1): 9p locks: add mount option for lock retry interval Dominique Martinet (12): 9p/xen: fix check for xenbus_read error in front_probe v9fs_dir_readdir: fix double-free on p9stat_read error 9p: clear dangling pointers in p9stat_free 9p: embed fcall in req to round down buffer allocs 9p: add a per-client fcall kmem_cache 9p/rdma: do not disconnect on down_interruptible EAGAIN 9p: acl: fix uninitialized iattr access 9p/rdma: remove useless check in cm_event_handler 9p: p9dirent_read: check network-provided name length 9p locks: fix glock.client_id leak in do_lock 9p/trans_fd: abort p9_read_work if req status changed 9p/trans_fd: put worker reqs on destroy Gertjan Halkes (1): 9p: do not trust pdu content for stat item size Gustavo A. R. Silva (1): 9p: fix spelling mistake in fall-through annotation Matthew Wilcox (2): 9p: Use a slab for allocating requests 9p: Remove p9_idpool Tomas Bortoli (3): 9p: rename p9_free_req() function 9p: Add refcount to p9_req_t 9p: Rename req to rreq in trans_fd fs/9p/acl.c | 2 +- fs/9p/v9fs.c | 21 +++++ fs/9p/v9fs.h | 1 + fs/9p/vfs_dir.c | 19 +--- fs/9p/vfs_file.c | 24 +++++- include/net/9p/9p.h | 12 +-- include/net/9p/client.h | 71 ++++++--------- net/9p/Makefile | 1 - net/9p/client.c | 551 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------------------------- net/9p/mod.c | 9 +- net/9p/protocol.c | 20 ++++- net/9p/trans_fd.c | 64 +++++++++----- net/9p/trans_rdma.c | 37 ++++---- net/9p/trans_virtio.c | 44 +++++++--- net/9p/trans_xen.c | 17 ++-- net/9p/util.c | 140 ------------------------------ 16 files changed, 482 insertions(+), 551 deletions(-) delete mode 100644 net/9p/util.c -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE/IPbcYBuWt0zoYhOq06b7GqY5nAFAlvWYE0ACgkQq06b7GqY 5nBBDxAAkz4rGRsnRpx9D1Bt+81eARTqsWcoPM138zEbwiJehe5aSF8x/CGyirDW +PoES/efho50sDfaUL9eBMgyy95UMN7LepMTcjNE1tywA+tRsH3dOL4757+lBwZc FGsHvfse4b5ZzmMxSo2L5KbzpNiUEXCJGEvNlBSbeWcSSUtCfOShMVx9IC6r7JhX pbsoczQ6W+384V4WgBxBZZf99EryxSeYJ9KMU+9b13ndzKICJqYeaEdItt28uYUC d05iXDEDQZD3B8R/1Y08ktMqmHLXP9kZdJ/w8HhCMRAxWKUD1pfDwJ45gIwhCb5R KxdxZ2tPvc8ihGngNJ4VaJoQQFTVzDgbyWXjwAFYkFUuPFgmuAgx3qApOhUFHCdM 8vgJd2u0attNwfOM3VsJApLQu09wmRw1LcmJ9re5OJ/YLiAUF3vw2oTpGhGlKRRI bMBI9rwXHzeoVI7ank5mh1NMVRpMbzL9A8uqux85gcpXL36V3XmZtKRDe1AAa5jB JR6dciAUABm9m+Ilt1Pl/faSjmysUOb1wZ0XU/cvVy5EBMUjbHv3x0TuDmrVwDas puUXEM8soVf9e/NUYqTOozwFIle6KFcyPmae/OopATLgkGES4cjDy9cLh5SgnERM vMcN/Z+DQO98zM/fPRy2B4qklflgTKI6VI/gSLRCWGpn49Iwhhg= =g1OF -----END PGP SIGNATURE----- Merge tag '9p-for-4.20' of git://github.com/martinetd/linux Pull 9p updates from Dominique Martinet: "Highlights this time around are the end of Matthew's work to remove the custom 9p request cache and use a slab directly for requests, with some extra patches on my end to not degrade performance, but it's a very good cleanup. Tomas and I fixed a few more syzkaller bugs (refcount is the big one), and I had a go at the coverity bugs and at some of the bugzilla reports we had open for a while. I'm a bit disappointed that I couldn't get much reviews for a few of my own patches, but the big ones got some and it's all been soaking in linux-next for quite a while so I think it should be OK. Summary: - Finish removing the custom 9p request cache mechanism - Embed part of the fcall in the request to have better slab performance (msize usually is power of two aligned) - syzkaller fixes: * add a refcount to 9p requests to avoid use after free * a few double free issues - A few coverity fixes - Some old patches that were in the bugzilla: * do not trust pdu content for size header * mount option for lock retry interval" * tag '9p-for-4.20' of git://github.com/martinetd/linux: (21 commits) 9p/trans_fd: put worker reqs on destroy 9p/trans_fd: abort p9_read_work if req status changed 9p: potential NULL dereference 9p locks: fix glock.client_id leak in do_lock 9p: p9dirent_read: check network-provided name length 9p/rdma: remove useless check in cm_event_handler 9p: acl: fix uninitialized iattr access 9p locks: add mount option for lock retry interval 9p: do not trust pdu content for stat item size 9p: Rename req to rreq in trans_fd 9p: fix spelling mistake in fall-through annotation 9p/rdma: do not disconnect on down_interruptible EAGAIN 9p: Add refcount to p9_req_t 9p: rename p9_free_req() function 9p: add a per-client fcall kmem_cache 9p: embed fcall in req to round down buffer allocs 9p: Remove p9_idpool 9p: Use a slab for allocating requests 9p: clear dangling pointers in p9stat_free v9fs_dir_readdir: fix double-free on p9stat_read error ...
This commit is contained in:
commit
7da4221b53
@ -276,7 +276,7 @@ static int v9fs_xattr_set_acl(const struct xattr_handler *handler,
|
||||
switch (handler->flags) {
|
||||
case ACL_TYPE_ACCESS:
|
||||
if (acl) {
|
||||
struct iattr iattr;
|
||||
struct iattr iattr = { 0 };
|
||||
struct posix_acl *old_acl = acl;
|
||||
|
||||
retval = posix_acl_update_mode(inode, &iattr.ia_mode, &acl);
|
||||
|
21
fs/9p/v9fs.c
21
fs/9p/v9fs.c
@ -61,6 +61,8 @@ enum {
|
||||
Opt_cache_loose, Opt_fscache, Opt_mmap,
|
||||
/* Access options */
|
||||
Opt_access, Opt_posixacl,
|
||||
/* Lock timeout option */
|
||||
Opt_locktimeout,
|
||||
/* Error token */
|
||||
Opt_err
|
||||
};
|
||||
@ -80,6 +82,7 @@ static const match_table_t tokens = {
|
||||
{Opt_cachetag, "cachetag=%s"},
|
||||
{Opt_access, "access=%s"},
|
||||
{Opt_posixacl, "posixacl"},
|
||||
{Opt_locktimeout, "locktimeout=%u"},
|
||||
{Opt_err, NULL}
|
||||
};
|
||||
|
||||
@ -187,6 +190,7 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
|
||||
#ifdef CONFIG_9P_FSCACHE
|
||||
v9ses->cachetag = NULL;
|
||||
#endif
|
||||
v9ses->session_lock_timeout = P9_LOCK_TIMEOUT;
|
||||
|
||||
if (!opts)
|
||||
return 0;
|
||||
@ -359,6 +363,23 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
|
||||
#endif
|
||||
break;
|
||||
|
||||
case Opt_locktimeout:
|
||||
r = match_int(&args[0], &option);
|
||||
if (r < 0) {
|
||||
p9_debug(P9_DEBUG_ERROR,
|
||||
"integer field, but no integer?\n");
|
||||
ret = r;
|
||||
continue;
|
||||
}
|
||||
if (option < 1) {
|
||||
p9_debug(P9_DEBUG_ERROR,
|
||||
"locktimeout must be a greater than zero integer.\n");
|
||||
ret = -EINVAL;
|
||||
continue;
|
||||
}
|
||||
v9ses->session_lock_timeout = (long)option * HZ;
|
||||
break;
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
@ -116,6 +116,7 @@ struct v9fs_session_info {
|
||||
struct p9_client *clnt; /* 9p client */
|
||||
struct list_head slist; /* list of sessions registered with v9fs */
|
||||
struct rw_semaphore rename_sem;
|
||||
long session_lock_timeout; /* retry interval for blocking locks */
|
||||
};
|
||||
|
||||
/* cache_validity flags */
|
||||
|
@ -76,15 +76,6 @@ static inline int dt_type(struct p9_wstat *mistat)
|
||||
return rettype;
|
||||
}
|
||||
|
||||
static void p9stat_init(struct p9_wstat *stbuf)
|
||||
{
|
||||
stbuf->name = NULL;
|
||||
stbuf->uid = NULL;
|
||||
stbuf->gid = NULL;
|
||||
stbuf->muid = NULL;
|
||||
stbuf->extension = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* v9fs_alloc_rdir_buf - Allocate buffer used for read and readdir
|
||||
* @filp: opened file structure
|
||||
@ -114,7 +105,6 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
|
||||
int err = 0;
|
||||
struct p9_fid *fid;
|
||||
int buflen;
|
||||
int reclen = 0;
|
||||
struct p9_rdir *rdir;
|
||||
struct kvec kvec;
|
||||
|
||||
@ -145,15 +135,12 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
|
||||
rdir->tail = n;
|
||||
}
|
||||
while (rdir->head < rdir->tail) {
|
||||
p9stat_init(&st);
|
||||
err = p9stat_read(fid->clnt, rdir->buf + rdir->head,
|
||||
rdir->tail - rdir->head, &st);
|
||||
if (err) {
|
||||
if (err <= 0) {
|
||||
p9_debug(P9_DEBUG_VFS, "returned %d\n", err);
|
||||
p9stat_free(&st);
|
||||
return -EIO;
|
||||
}
|
||||
reclen = st.size+2;
|
||||
|
||||
over = !dir_emit(ctx, st.name, strlen(st.name),
|
||||
v9fs_qid2ino(&st.qid), dt_type(&st));
|
||||
@ -161,8 +148,8 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
|
||||
if (over)
|
||||
return 0;
|
||||
|
||||
rdir->head += reclen;
|
||||
ctx->pos += reclen;
|
||||
rdir->head += err;
|
||||
ctx->pos += err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -154,6 +154,7 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
|
||||
uint8_t status = P9_LOCK_ERROR;
|
||||
int res = 0;
|
||||
unsigned char fl_type;
|
||||
struct v9fs_session_info *v9ses;
|
||||
|
||||
fid = filp->private_data;
|
||||
BUG_ON(fid == NULL);
|
||||
@ -189,6 +190,8 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
|
||||
if (IS_SETLKW(cmd))
|
||||
flock.flags = P9_LOCK_FLAGS_BLOCK;
|
||||
|
||||
v9ses = v9fs_inode2v9ses(file_inode(filp));
|
||||
|
||||
/*
|
||||
* if its a blocked request and we get P9_LOCK_BLOCKED as the status
|
||||
* for lock request, keep on trying
|
||||
@ -202,8 +205,17 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
|
||||
break;
|
||||
if (status == P9_LOCK_BLOCKED && !IS_SETLKW(cmd))
|
||||
break;
|
||||
if (schedule_timeout_interruptible(P9_LOCK_TIMEOUT) != 0)
|
||||
if (schedule_timeout_interruptible(v9ses->session_lock_timeout)
|
||||
!= 0)
|
||||
break;
|
||||
/*
|
||||
* p9_client_lock_dotl overwrites flock.client_id with the
|
||||
* server message, free and reuse the client name
|
||||
*/
|
||||
if (flock.client_id != fid->clnt->name) {
|
||||
kfree(flock.client_id);
|
||||
flock.client_id = fid->clnt->name;
|
||||
}
|
||||
}
|
||||
|
||||
/* map 9p status to VFS status */
|
||||
@ -216,7 +228,7 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
|
||||
break;
|
||||
default:
|
||||
WARN_ONCE(1, "unknown lock status code: %d\n", status);
|
||||
/* fallthough */
|
||||
/* fall through */
|
||||
case P9_LOCK_ERROR:
|
||||
case P9_LOCK_GRACE:
|
||||
res = -ENOLCK;
|
||||
@ -235,6 +247,8 @@ out_unlock:
|
||||
locks_lock_file_wait(filp, fl);
|
||||
fl->fl_type = fl_type;
|
||||
}
|
||||
if (flock.client_id != fid->clnt->name)
|
||||
kfree(flock.client_id);
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
@ -269,7 +283,7 @@ static int v9fs_file_getlock(struct file *filp, struct file_lock *fl)
|
||||
|
||||
res = p9_client_getlock_dotl(fid, &glock);
|
||||
if (res < 0)
|
||||
return res;
|
||||
goto out;
|
||||
/* map 9p lock type to os lock type */
|
||||
switch (glock.type) {
|
||||
case P9_LOCK_TYPE_RDLCK:
|
||||
@ -290,7 +304,9 @@ static int v9fs_file_getlock(struct file *filp, struct file_lock *fl)
|
||||
fl->fl_end = glock.start + glock.length - 1;
|
||||
fl->fl_pid = -glock.proc_id;
|
||||
}
|
||||
kfree(glock.client_id);
|
||||
out:
|
||||
if (glock.client_id != fid->clnt->name)
|
||||
kfree(glock.client_id);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -336,6 +336,9 @@ enum p9_qid_t {
|
||||
#define P9_NOFID (u32)(~0)
|
||||
#define P9_MAXWELEM 16
|
||||
|
||||
/* Minimal header size: size[4] type[1] tag[2] */
|
||||
#define P9_HDRSZ 7
|
||||
|
||||
/* ample room for Twrite/Rread header */
|
||||
#define P9_IOHDRSZ 24
|
||||
|
||||
@ -558,19 +561,12 @@ struct p9_fcall {
|
||||
size_t offset;
|
||||
size_t capacity;
|
||||
|
||||
struct kmem_cache *cache;
|
||||
u8 *sdata;
|
||||
};
|
||||
|
||||
struct p9_idpool;
|
||||
|
||||
int p9_errstr2errno(char *errstr, int len);
|
||||
|
||||
struct p9_idpool *p9_idpool_create(void);
|
||||
void p9_idpool_destroy(struct p9_idpool *);
|
||||
int p9_idpool_get(struct p9_idpool *p);
|
||||
void p9_idpool_put(int id, struct p9_idpool *p);
|
||||
int p9_idpool_check(int id, struct p9_idpool *p);
|
||||
|
||||
int p9_error_init(void);
|
||||
int p9_trans_fd_init(void);
|
||||
void p9_trans_fd_exit(void);
|
||||
|
@ -64,22 +64,15 @@ enum p9_trans_status {
|
||||
|
||||
/**
|
||||
* enum p9_req_status_t - status of a request
|
||||
* @REQ_STATUS_IDLE: request slot unused
|
||||
* @REQ_STATUS_ALLOC: request has been allocated but not sent
|
||||
* @REQ_STATUS_UNSENT: request waiting to be sent
|
||||
* @REQ_STATUS_SENT: request sent to server
|
||||
* @REQ_STATUS_RCVD: response received from server
|
||||
* @REQ_STATUS_FLSHD: request has been flushed
|
||||
* @REQ_STATUS_ERROR: request encountered an error on the client side
|
||||
*
|
||||
* The @REQ_STATUS_IDLE state is used to mark a request slot as unused
|
||||
* but use is actually tracked by the idpool structure which handles tag
|
||||
* id allocation.
|
||||
*
|
||||
*/
|
||||
|
||||
enum p9_req_status_t {
|
||||
REQ_STATUS_IDLE,
|
||||
REQ_STATUS_ALLOC,
|
||||
REQ_STATUS_UNSENT,
|
||||
REQ_STATUS_SENT,
|
||||
@ -92,70 +85,46 @@ 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
|
||||
* @aux: transport specific data (provided for trans_fd migration)
|
||||
* @req_list: link for higher level objects to chain requests
|
||||
*
|
||||
* Transport use an array to track outstanding requests
|
||||
* instead of a list. While this may incurr overhead during initial
|
||||
* allocation or expansion, it makes request lookup much easier as the
|
||||
* tag id is a index into an array. (We use tag+1 so that we can accommodate
|
||||
* the -1 tag for the T_VERSION request).
|
||||
* This also has the nice effect of only having to allocate wait_queues
|
||||
* once, instead of constantly allocating and freeing them. Its possible
|
||||
* other resources could benefit from this scheme as well.
|
||||
*
|
||||
*/
|
||||
|
||||
struct p9_req_t {
|
||||
int status;
|
||||
int t_err;
|
||||
struct kref refcount;
|
||||
wait_queue_head_t wq;
|
||||
struct p9_fcall *tc;
|
||||
struct p9_fcall *rc;
|
||||
struct p9_fcall tc;
|
||||
struct p9_fcall rc;
|
||||
void *aux;
|
||||
|
||||
struct list_head req_list;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct p9_client - per client instance state
|
||||
* @lock: protect @fidlist
|
||||
* @lock: protect @fids and @reqs
|
||||
* @msize: maximum data size negotiated by protocol
|
||||
* @dotu: extension flags negotiated by protocol
|
||||
* @proto_version: 9P protocol version to use
|
||||
* @trans_mod: module API instantiated with this client
|
||||
* @status: connection state
|
||||
* @trans: tranport instance state and API
|
||||
* @fids: All active FID handles
|
||||
* @tagpool - transaction id accounting for session
|
||||
* @reqs - 2D array of requests
|
||||
* @max_tag - current maximum tag id allocated
|
||||
* @name - node name used as client id
|
||||
* @reqs: All active requests.
|
||||
* @name: node name used as client id
|
||||
*
|
||||
* The client structure is used to keep track of various per-client
|
||||
* state that has been instantiated.
|
||||
* In order to minimize per-transaction overhead we use a
|
||||
* simple array to lookup requests instead of a hash table
|
||||
* or linked list. In order to support larger number of
|
||||
* transactions, we make this a 2D array, allocating new rows
|
||||
* when we need to grow the total number of the transactions.
|
||||
*
|
||||
* Each row is 256 requests and we'll support up to 256 rows for
|
||||
* a total of 64k concurrent requests per session.
|
||||
*
|
||||
* Bugs: duplicated data and potentially unnecessary elements.
|
||||
*/
|
||||
|
||||
struct p9_client {
|
||||
spinlock_t lock; /* protect client structure */
|
||||
spinlock_t lock;
|
||||
unsigned int msize;
|
||||
unsigned char proto_version;
|
||||
struct p9_trans_module *trans_mod;
|
||||
enum p9_trans_status status;
|
||||
void *trans;
|
||||
struct kmem_cache *fcall_cache;
|
||||
|
||||
union {
|
||||
struct {
|
||||
@ -170,10 +139,7 @@ struct p9_client {
|
||||
} trans_opts;
|
||||
|
||||
struct idr fids;
|
||||
|
||||
struct p9_idpool *tagpool;
|
||||
struct p9_req_t *reqs[P9_ROW_MAXTAG];
|
||||
int max_tag;
|
||||
struct idr reqs;
|
||||
|
||||
char name[__NEW_UTS_LEN + 1];
|
||||
};
|
||||
@ -266,7 +232,21 @@ int p9_client_mkdir_dotl(struct p9_fid *fid, const char *name, int mode,
|
||||
kgid_t gid, struct p9_qid *);
|
||||
int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status);
|
||||
int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *fl);
|
||||
void p9_fcall_fini(struct p9_fcall *fc);
|
||||
struct p9_req_t *p9_tag_lookup(struct p9_client *, u16);
|
||||
|
||||
static inline void p9_req_get(struct p9_req_t *r)
|
||||
{
|
||||
kref_get(&r->refcount);
|
||||
}
|
||||
|
||||
static inline int p9_req_try_get(struct p9_req_t *r)
|
||||
{
|
||||
return kref_get_unless_zero(&r->refcount);
|
||||
}
|
||||
|
||||
int p9_req_put(struct p9_req_t *r);
|
||||
|
||||
void p9_client_cb(struct p9_client *c, struct p9_req_t *req, int status);
|
||||
|
||||
int p9_parse_header(struct p9_fcall *, int32_t *, int8_t *, int16_t *, int);
|
||||
@ -279,4 +259,7 @@ struct p9_fid *p9_client_xattrwalk(struct p9_fid *, const char *, u64 *);
|
||||
int p9_client_xattrcreate(struct p9_fid *, const char *, u64, int);
|
||||
int p9_client_readlink(struct p9_fid *fid, char **target);
|
||||
|
||||
int p9_client_init(void);
|
||||
void p9_client_exit(void);
|
||||
|
||||
#endif /* NET_9P_CLIENT_H */
|
||||
|
@ -8,7 +8,6 @@ obj-$(CONFIG_NET_9P_RDMA) += 9pnet_rdma.o
|
||||
mod.o \
|
||||
client.o \
|
||||
error.o \
|
||||
util.o \
|
||||
protocol.o \
|
||||
trans_fd.o \
|
||||
trans_common.o \
|
||||
|
561
net/9p/client.c
561
net/9p/client.c
File diff suppressed because it is too large
Load Diff
@ -171,11 +171,17 @@ void v9fs_put_trans(struct p9_trans_module *m)
|
||||
*/
|
||||
static int __init init_p9(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = p9_client_init();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
p9_error_init();
|
||||
pr_info("Installing 9P2000 support\n");
|
||||
p9_trans_fd_init();
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -188,6 +194,7 @@ static void __exit exit_p9(void)
|
||||
pr_info("Unloading 9P2000 support\n");
|
||||
|
||||
p9_trans_fd_exit();
|
||||
p9_client_exit();
|
||||
}
|
||||
|
||||
module_init(init_p9)
|
||||
|
@ -46,10 +46,15 @@ p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);
|
||||
void p9stat_free(struct p9_wstat *stbuf)
|
||||
{
|
||||
kfree(stbuf->name);
|
||||
stbuf->name = NULL;
|
||||
kfree(stbuf->uid);
|
||||
stbuf->uid = NULL;
|
||||
kfree(stbuf->gid);
|
||||
stbuf->gid = NULL;
|
||||
kfree(stbuf->muid);
|
||||
stbuf->muid = NULL;
|
||||
kfree(stbuf->extension);
|
||||
stbuf->extension = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(p9stat_free);
|
||||
|
||||
@ -566,9 +571,10 @@ int p9stat_read(struct p9_client *clnt, char *buf, int len, struct p9_wstat *st)
|
||||
if (ret) {
|
||||
p9_debug(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
|
||||
trace_9p_protocol_dump(clnt, &fake_pdu);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return fake_pdu.offset;
|
||||
}
|
||||
EXPORT_SYMBOL(p9stat_read);
|
||||
|
||||
@ -617,13 +623,19 @@ int p9dirent_read(struct p9_client *clnt, char *buf, int len,
|
||||
if (ret) {
|
||||
p9_debug(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret);
|
||||
trace_9p_protocol_dump(clnt, &fake_pdu);
|
||||
goto out;
|
||||
return ret;
|
||||
}
|
||||
|
||||
strcpy(dirent->d_name, nameptr);
|
||||
ret = strscpy(dirent->d_name, nameptr, sizeof(dirent->d_name));
|
||||
if (ret < 0) {
|
||||
p9_debug(P9_DEBUG_ERROR,
|
||||
"On the wire dirent name too long: %s\n",
|
||||
nameptr);
|
||||
kfree(nameptr);
|
||||
return ret;
|
||||
}
|
||||
kfree(nameptr);
|
||||
|
||||
out:
|
||||
return fake_pdu.offset;
|
||||
}
|
||||
EXPORT_SYMBOL(p9dirent_read);
|
||||
|
@ -131,7 +131,8 @@ struct p9_conn {
|
||||
int err;
|
||||
struct list_head req_list;
|
||||
struct list_head unsent_req_list;
|
||||
struct p9_req_t *req;
|
||||
struct p9_req_t *rreq;
|
||||
struct p9_req_t *wreq;
|
||||
char tmp_buf[7];
|
||||
struct p9_fcall rc;
|
||||
int wpos;
|
||||
@ -291,7 +292,6 @@ static void p9_read_work(struct work_struct *work)
|
||||
__poll_t n;
|
||||
int err;
|
||||
struct p9_conn *m;
|
||||
int status = REQ_STATUS_ERROR;
|
||||
|
||||
m = container_of(work, struct p9_conn, rq);
|
||||
|
||||
@ -322,7 +322,7 @@ static void p9_read_work(struct work_struct *work)
|
||||
m->rc.offset += err;
|
||||
|
||||
/* header read in */
|
||||
if ((!m->req) && (m->rc.offset == m->rc.capacity)) {
|
||||
if ((!m->rreq) && (m->rc.offset == m->rc.capacity)) {
|
||||
p9_debug(P9_DEBUG_TRANS, "got new header\n");
|
||||
|
||||
/* Header size */
|
||||
@ -346,23 +346,23 @@ static void p9_read_work(struct work_struct *work)
|
||||
"mux %p pkt: size: %d bytes tag: %d\n",
|
||||
m, m->rc.size, m->rc.tag);
|
||||
|
||||
m->req = p9_tag_lookup(m->client, m->rc.tag);
|
||||
if (!m->req || (m->req->status != REQ_STATUS_SENT)) {
|
||||
m->rreq = p9_tag_lookup(m->client, m->rc.tag);
|
||||
if (!m->rreq || (m->rreq->status != REQ_STATUS_SENT)) {
|
||||
p9_debug(P9_DEBUG_ERROR, "Unexpected packet tag %d\n",
|
||||
m->rc.tag);
|
||||
err = -EIO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (m->req->rc == NULL) {
|
||||
if (!m->rreq->rc.sdata) {
|
||||
p9_debug(P9_DEBUG_ERROR,
|
||||
"No recv fcall for tag %d (req %p), disconnecting!\n",
|
||||
m->rc.tag, m->req);
|
||||
m->req = NULL;
|
||||
m->rc.tag, m->rreq);
|
||||
m->rreq = NULL;
|
||||
err = -EIO;
|
||||
goto error;
|
||||
}
|
||||
m->rc.sdata = (char *)m->req->rc + sizeof(struct p9_fcall);
|
||||
m->rc.sdata = m->rreq->rc.sdata;
|
||||
memcpy(m->rc.sdata, m->tmp_buf, m->rc.capacity);
|
||||
m->rc.capacity = m->rc.size;
|
||||
}
|
||||
@ -370,20 +370,27 @@ static void p9_read_work(struct work_struct *work)
|
||||
/* packet is read in
|
||||
* not an else because some packets (like clunk) have no payload
|
||||
*/
|
||||
if ((m->req) && (m->rc.offset == m->rc.capacity)) {
|
||||
if ((m->rreq) && (m->rc.offset == m->rc.capacity)) {
|
||||
p9_debug(P9_DEBUG_TRANS, "got new packet\n");
|
||||
m->req->rc->size = m->rc.offset;
|
||||
m->rreq->rc.size = m->rc.offset;
|
||||
spin_lock(&m->client->lock);
|
||||
if (m->req->status != REQ_STATUS_ERROR)
|
||||
status = REQ_STATUS_RCVD;
|
||||
list_del(&m->req->req_list);
|
||||
/* update req->status while holding client->lock */
|
||||
p9_client_cb(m->client, m->req, status);
|
||||
if (m->rreq->status == REQ_STATUS_SENT) {
|
||||
list_del(&m->rreq->req_list);
|
||||
p9_client_cb(m->client, m->rreq, REQ_STATUS_RCVD);
|
||||
} else {
|
||||
spin_unlock(&m->client->lock);
|
||||
p9_debug(P9_DEBUG_ERROR,
|
||||
"Request tag %d errored out while we were reading the reply\n",
|
||||
m->rc.tag);
|
||||
err = -EIO;
|
||||
goto error;
|
||||
}
|
||||
spin_unlock(&m->client->lock);
|
||||
m->rc.sdata = NULL;
|
||||
m->rc.offset = 0;
|
||||
m->rc.capacity = 0;
|
||||
m->req = NULL;
|
||||
p9_req_put(m->rreq);
|
||||
m->rreq = NULL;
|
||||
}
|
||||
|
||||
end_clear:
|
||||
@ -469,9 +476,11 @@ static void p9_write_work(struct work_struct *work)
|
||||
p9_debug(P9_DEBUG_TRANS, "move req %p\n", req);
|
||||
list_move_tail(&req->req_list, &m->req_list);
|
||||
|
||||
m->wbuf = req->tc->sdata;
|
||||
m->wsize = req->tc->size;
|
||||
m->wbuf = req->tc.sdata;
|
||||
m->wsize = req->tc.size;
|
||||
m->wpos = 0;
|
||||
p9_req_get(req);
|
||||
m->wreq = req;
|
||||
spin_unlock(&m->client->lock);
|
||||
}
|
||||
|
||||
@ -492,8 +501,11 @@ static void p9_write_work(struct work_struct *work)
|
||||
}
|
||||
|
||||
m->wpos += err;
|
||||
if (m->wpos == m->wsize)
|
||||
if (m->wpos == m->wsize) {
|
||||
m->wpos = m->wsize = 0;
|
||||
p9_req_put(m->wreq);
|
||||
m->wreq = NULL;
|
||||
}
|
||||
|
||||
end_clear:
|
||||
clear_bit(Wworksched, &m->wsched);
|
||||
@ -663,7 +675,7 @@ static int p9_fd_request(struct p9_client *client, struct p9_req_t *req)
|
||||
struct p9_conn *m = &ts->conn;
|
||||
|
||||
p9_debug(P9_DEBUG_TRANS, "mux %p task %p tcall %p id %d\n",
|
||||
m, current, req->tc, req->tc->id);
|
||||
m, current, &req->tc, req->tc.id);
|
||||
if (m->err < 0)
|
||||
return m->err;
|
||||
|
||||
@ -694,6 +706,7 @@ static int p9_fd_cancel(struct p9_client *client, struct p9_req_t *req)
|
||||
if (req->status == REQ_STATUS_UNSENT) {
|
||||
list_del(&req->req_list);
|
||||
req->status = REQ_STATUS_FLSHD;
|
||||
p9_req_put(req);
|
||||
ret = 0;
|
||||
}
|
||||
spin_unlock(&client->lock);
|
||||
@ -711,6 +724,7 @@ static int p9_fd_cancelled(struct p9_client *client, struct p9_req_t *req)
|
||||
spin_lock(&client->lock);
|
||||
list_del(&req->req_list);
|
||||
spin_unlock(&client->lock);
|
||||
p9_req_put(req);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -862,7 +876,15 @@ static void p9_conn_destroy(struct p9_conn *m)
|
||||
|
||||
p9_mux_poll_stop(m);
|
||||
cancel_work_sync(&m->rq);
|
||||
if (m->rreq) {
|
||||
p9_req_put(m->rreq);
|
||||
m->rreq = NULL;
|
||||
}
|
||||
cancel_work_sync(&m->wq);
|
||||
if (m->wreq) {
|
||||
p9_req_put(m->wreq);
|
||||
m->wreq = NULL;
|
||||
}
|
||||
|
||||
p9_conn_cancel(m, -ECONNRESET);
|
||||
|
||||
|
@ -122,7 +122,7 @@ struct p9_rdma_context {
|
||||
dma_addr_t busa;
|
||||
union {
|
||||
struct p9_req_t *req;
|
||||
struct p9_fcall *rc;
|
||||
struct p9_fcall rc;
|
||||
};
|
||||
};
|
||||
|
||||
@ -274,8 +274,7 @@ p9_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event)
|
||||
case RDMA_CM_EVENT_DISCONNECTED:
|
||||
if (rdma)
|
||||
rdma->state = P9_RDMA_CLOSED;
|
||||
if (c)
|
||||
c->status = Disconnected;
|
||||
c->status = Disconnected;
|
||||
break;
|
||||
|
||||
case RDMA_CM_EVENT_TIMEWAIT_EXIT:
|
||||
@ -320,8 +319,8 @@ recv_done(struct ib_cq *cq, struct ib_wc *wc)
|
||||
if (wc->status != IB_WC_SUCCESS)
|
||||
goto err_out;
|
||||
|
||||
c->rc->size = wc->byte_len;
|
||||
err = p9_parse_header(c->rc, NULL, NULL, &tag, 1);
|
||||
c->rc.size = wc->byte_len;
|
||||
err = p9_parse_header(&c->rc, NULL, NULL, &tag, 1);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
@ -331,12 +330,13 @@ recv_done(struct ib_cq *cq, struct ib_wc *wc)
|
||||
|
||||
/* Check that we have not yet received a reply for this request.
|
||||
*/
|
||||
if (unlikely(req->rc)) {
|
||||
if (unlikely(req->rc.sdata)) {
|
||||
pr_err("Duplicate reply for request %d", tag);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
req->rc = c->rc;
|
||||
req->rc.size = c->rc.size;
|
||||
req->rc.sdata = c->rc.sdata;
|
||||
p9_client_cb(client, req, REQ_STATUS_RCVD);
|
||||
|
||||
out:
|
||||
@ -361,9 +361,10 @@ send_done(struct ib_cq *cq, struct ib_wc *wc)
|
||||
container_of(wc->wr_cqe, struct p9_rdma_context, cqe);
|
||||
|
||||
ib_dma_unmap_single(rdma->cm_id->device,
|
||||
c->busa, c->req->tc->size,
|
||||
c->busa, c->req->tc.size,
|
||||
DMA_TO_DEVICE);
|
||||
up(&rdma->sq_sem);
|
||||
p9_req_put(c->req);
|
||||
kfree(c);
|
||||
}
|
||||
|
||||
@ -401,7 +402,7 @@ post_recv(struct p9_client *client, struct p9_rdma_context *c)
|
||||
struct ib_sge sge;
|
||||
|
||||
c->busa = ib_dma_map_single(rdma->cm_id->device,
|
||||
c->rc->sdata, client->msize,
|
||||
c->rc.sdata, client->msize,
|
||||
DMA_FROM_DEVICE);
|
||||
if (ib_dma_mapping_error(rdma->cm_id->device, c->busa))
|
||||
goto error;
|
||||
@ -443,9 +444,9 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
|
||||
**/
|
||||
if (unlikely(atomic_read(&rdma->excess_rc) > 0)) {
|
||||
if ((atomic_sub_return(1, &rdma->excess_rc) >= 0)) {
|
||||
/* Got one ! */
|
||||
kfree(req->rc);
|
||||
req->rc = NULL;
|
||||
/* Got one! */
|
||||
p9_fcall_fini(&req->rc);
|
||||
req->rc.sdata = NULL;
|
||||
goto dont_need_post_recv;
|
||||
} else {
|
||||
/* We raced and lost. */
|
||||
@ -459,7 +460,7 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
|
||||
err = -ENOMEM;
|
||||
goto recv_error;
|
||||
}
|
||||
rpl_context->rc = req->rc;
|
||||
rpl_context->rc.sdata = req->rc.sdata;
|
||||
|
||||
/*
|
||||
* Post a receive buffer for this request. We need to ensure
|
||||
@ -475,11 +476,11 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
|
||||
|
||||
err = post_recv(client, rpl_context);
|
||||
if (err) {
|
||||
p9_debug(P9_DEBUG_FCALL, "POST RECV failed\n");
|
||||
p9_debug(P9_DEBUG_ERROR, "POST RECV failed: %d\n", err);
|
||||
goto recv_error;
|
||||
}
|
||||
/* remove posted receive buffer from request structure */
|
||||
req->rc = NULL;
|
||||
req->rc.sdata = NULL;
|
||||
|
||||
dont_need_post_recv:
|
||||
/* Post the request */
|
||||
@ -491,7 +492,7 @@ dont_need_post_recv:
|
||||
c->req = req;
|
||||
|
||||
c->busa = ib_dma_map_single(rdma->cm_id->device,
|
||||
c->req->tc->sdata, c->req->tc->size,
|
||||
c->req->tc.sdata, c->req->tc.size,
|
||||
DMA_TO_DEVICE);
|
||||
if (ib_dma_mapping_error(rdma->cm_id->device, c->busa)) {
|
||||
err = -EIO;
|
||||
@ -501,7 +502,7 @@ dont_need_post_recv:
|
||||
c->cqe.done = send_done;
|
||||
|
||||
sge.addr = c->busa;
|
||||
sge.length = c->req->tc->size;
|
||||
sge.length = c->req->tc.size;
|
||||
sge.lkey = rdma->pd->local_dma_lkey;
|
||||
|
||||
wr.next = NULL;
|
||||
@ -544,7 +545,7 @@ dont_need_post_recv:
|
||||
recv_error:
|
||||
kfree(rpl_context);
|
||||
spin_lock_irqsave(&rdma->req_lock, flags);
|
||||
if (rdma->state < P9_RDMA_CLOSING) {
|
||||
if (err != -EINTR && rdma->state < P9_RDMA_CLOSING) {
|
||||
rdma->state = P9_RDMA_CLOSING;
|
||||
spin_unlock_irqrestore(&rdma->req_lock, flags);
|
||||
rdma_disconnect(rdma->cm_id);
|
||||
|
@ -155,7 +155,7 @@ static void req_done(struct virtqueue *vq)
|
||||
}
|
||||
|
||||
if (len) {
|
||||
req->rc->size = len;
|
||||
req->rc.size = len;
|
||||
p9_client_cb(chan->client, req, REQ_STATUS_RCVD);
|
||||
}
|
||||
}
|
||||
@ -207,6 +207,13 @@ static int p9_virtio_cancel(struct p9_client *client, struct p9_req_t *req)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Reply won't come, so drop req ref */
|
||||
static int p9_virtio_cancelled(struct p9_client *client, struct p9_req_t *req)
|
||||
{
|
||||
p9_req_put(req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* pack_sg_list_p - Just like pack_sg_list. Instead of taking a buffer,
|
||||
* this takes a list of pages.
|
||||
@ -273,12 +280,12 @@ req_retry:
|
||||
out_sgs = in_sgs = 0;
|
||||
/* Handle out VirtIO ring buffers */
|
||||
out = pack_sg_list(chan->sg, 0,
|
||||
VIRTQUEUE_NUM, req->tc->sdata, req->tc->size);
|
||||
VIRTQUEUE_NUM, req->tc.sdata, req->tc.size);
|
||||
if (out)
|
||||
sgs[out_sgs++] = chan->sg;
|
||||
|
||||
in = pack_sg_list(chan->sg, out,
|
||||
VIRTQUEUE_NUM, req->rc->sdata, req->rc->capacity);
|
||||
VIRTQUEUE_NUM, req->rc.sdata, req->rc.capacity);
|
||||
if (in)
|
||||
sgs[out_sgs + in_sgs++] = chan->sg + out;
|
||||
|
||||
@ -404,6 +411,7 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req,
|
||||
struct scatterlist *sgs[4];
|
||||
size_t offs;
|
||||
int need_drop = 0;
|
||||
int kicked = 0;
|
||||
|
||||
p9_debug(P9_DEBUG_TRANS, "virtio request\n");
|
||||
|
||||
@ -411,29 +419,33 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req,
|
||||
__le32 sz;
|
||||
int n = p9_get_mapped_pages(chan, &out_pages, uodata,
|
||||
outlen, &offs, &need_drop);
|
||||
if (n < 0)
|
||||
return n;
|
||||
if (n < 0) {
|
||||
err = n;
|
||||
goto err_out;
|
||||
}
|
||||
out_nr_pages = DIV_ROUND_UP(n + offs, PAGE_SIZE);
|
||||
if (n != outlen) {
|
||||
__le32 v = cpu_to_le32(n);
|
||||
memcpy(&req->tc->sdata[req->tc->size - 4], &v, 4);
|
||||
memcpy(&req->tc.sdata[req->tc.size - 4], &v, 4);
|
||||
outlen = n;
|
||||
}
|
||||
/* The size field of the message must include the length of the
|
||||
* header and the length of the data. We didn't actually know
|
||||
* the length of the data until this point so add it in now.
|
||||
*/
|
||||
sz = cpu_to_le32(req->tc->size + outlen);
|
||||
memcpy(&req->tc->sdata[0], &sz, sizeof(sz));
|
||||
sz = cpu_to_le32(req->tc.size + outlen);
|
||||
memcpy(&req->tc.sdata[0], &sz, sizeof(sz));
|
||||
} else if (uidata) {
|
||||
int n = p9_get_mapped_pages(chan, &in_pages, uidata,
|
||||
inlen, &offs, &need_drop);
|
||||
if (n < 0)
|
||||
return n;
|
||||
if (n < 0) {
|
||||
err = n;
|
||||
goto err_out;
|
||||
}
|
||||
in_nr_pages = DIV_ROUND_UP(n + offs, PAGE_SIZE);
|
||||
if (n != inlen) {
|
||||
__le32 v = cpu_to_le32(n);
|
||||
memcpy(&req->tc->sdata[req->tc->size - 4], &v, 4);
|
||||
memcpy(&req->tc.sdata[req->tc.size - 4], &v, 4);
|
||||
inlen = n;
|
||||
}
|
||||
}
|
||||
@ -445,7 +457,7 @@ req_retry_pinned:
|
||||
|
||||
/* out data */
|
||||
out = pack_sg_list(chan->sg, 0,
|
||||
VIRTQUEUE_NUM, req->tc->sdata, req->tc->size);
|
||||
VIRTQUEUE_NUM, req->tc.sdata, req->tc.size);
|
||||
|
||||
if (out)
|
||||
sgs[out_sgs++] = chan->sg;
|
||||
@ -464,7 +476,7 @@ req_retry_pinned:
|
||||
* alloced memory and payload onto the user buffer.
|
||||
*/
|
||||
in = pack_sg_list(chan->sg, out,
|
||||
VIRTQUEUE_NUM, req->rc->sdata, in_hdr_len);
|
||||
VIRTQUEUE_NUM, req->rc.sdata, in_hdr_len);
|
||||
if (in)
|
||||
sgs[out_sgs + in_sgs++] = chan->sg + out;
|
||||
|
||||
@ -498,6 +510,7 @@ req_retry_pinned:
|
||||
}
|
||||
virtqueue_kick(chan->vq);
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
kicked = 1;
|
||||
p9_debug(P9_DEBUG_TRANS, "virtio request kicked\n");
|
||||
err = wait_event_killable(req->wq, req->status >= REQ_STATUS_RCVD);
|
||||
/*
|
||||
@ -518,6 +531,10 @@ err_out:
|
||||
}
|
||||
kvfree(in_pages);
|
||||
kvfree(out_pages);
|
||||
if (!kicked) {
|
||||
/* reply won't come */
|
||||
p9_req_put(req);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -750,6 +767,7 @@ static struct p9_trans_module p9_virtio_trans = {
|
||||
.request = p9_virtio_request,
|
||||
.zc_request = p9_virtio_zc_request,
|
||||
.cancel = p9_virtio_cancel,
|
||||
.cancelled = p9_virtio_cancelled,
|
||||
/*
|
||||
* We leave one entry for input and one entry for response
|
||||
* headers. We also skip one more entry to accomodate, address
|
||||
|
@ -141,7 +141,7 @@ static int p9_xen_request(struct p9_client *client, struct p9_req_t *p9_req)
|
||||
struct xen_9pfs_front_priv *priv = NULL;
|
||||
RING_IDX cons, prod, masked_cons, masked_prod;
|
||||
unsigned long flags;
|
||||
u32 size = p9_req->tc->size;
|
||||
u32 size = p9_req->tc.size;
|
||||
struct xen_9pfs_dataring *ring;
|
||||
int num;
|
||||
|
||||
@ -154,7 +154,7 @@ static int p9_xen_request(struct p9_client *client, struct p9_req_t *p9_req)
|
||||
if (!priv || priv->client != client)
|
||||
return -EINVAL;
|
||||
|
||||
num = p9_req->tc->tag % priv->num_rings;
|
||||
num = p9_req->tc.tag % priv->num_rings;
|
||||
ring = &priv->rings[num];
|
||||
|
||||
again:
|
||||
@ -176,7 +176,7 @@ again:
|
||||
masked_prod = xen_9pfs_mask(prod, XEN_9PFS_RING_SIZE);
|
||||
masked_cons = xen_9pfs_mask(cons, XEN_9PFS_RING_SIZE);
|
||||
|
||||
xen_9pfs_write_packet(ring->data.out, p9_req->tc->sdata, size,
|
||||
xen_9pfs_write_packet(ring->data.out, p9_req->tc.sdata, size,
|
||||
&masked_prod, masked_cons, XEN_9PFS_RING_SIZE);
|
||||
|
||||
p9_req->status = REQ_STATUS_SENT;
|
||||
@ -185,6 +185,7 @@ again:
|
||||
ring->intf->out_prod = prod;
|
||||
spin_unlock_irqrestore(&ring->lock, flags);
|
||||
notify_remote_via_irq(ring->irq);
|
||||
p9_req_put(p9_req);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -229,12 +230,12 @@ static void p9_xen_response(struct work_struct *work)
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(req->rc, &h, sizeof(h));
|
||||
req->rc->offset = 0;
|
||||
memcpy(&req->rc, &h, sizeof(h));
|
||||
req->rc.offset = 0;
|
||||
|
||||
masked_cons = xen_9pfs_mask(cons, XEN_9PFS_RING_SIZE);
|
||||
/* Then, read the whole packet (including the header) */
|
||||
xen_9pfs_read_packet(req->rc->sdata, ring->data.in, h.size,
|
||||
xen_9pfs_read_packet(req->rc.sdata, ring->data.in, h.size,
|
||||
masked_prod, &masked_cons,
|
||||
XEN_9PFS_RING_SIZE);
|
||||
|
||||
@ -391,8 +392,8 @@ static int xen_9pfs_front_probe(struct xenbus_device *dev,
|
||||
unsigned int max_rings, max_ring_order, len = 0;
|
||||
|
||||
versions = xenbus_read(XBT_NIL, dev->otherend, "versions", &len);
|
||||
if (!len)
|
||||
return -EINVAL;
|
||||
if (IS_ERR(versions))
|
||||
return PTR_ERR(versions);
|
||||
if (strcmp(versions, "1")) {
|
||||
kfree(versions);
|
||||
return -EINVAL;
|
||||
|
140
net/9p/util.c
140
net/9p/util.c
@ -1,140 +0,0 @@
|
||||
/*
|
||||
* net/9p/util.c
|
||||
*
|
||||
* This file contains some helper functions
|
||||
*
|
||||
* Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
|
||||
* Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
|
||||
* Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to:
|
||||
* Free Software Foundation
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02111-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/parser.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/slab.h>
|
||||
#include <net/9p/9p.h>
|
||||
|
||||
/**
|
||||
* struct p9_idpool - per-connection accounting for tag idpool
|
||||
* @lock: protects the pool
|
||||
* @pool: idr to allocate tag id from
|
||||
*
|
||||
*/
|
||||
|
||||
struct p9_idpool {
|
||||
spinlock_t lock;
|
||||
struct idr pool;
|
||||
};
|
||||
|
||||
/**
|
||||
* p9_idpool_create - create a new per-connection id pool
|
||||
*
|
||||
*/
|
||||
|
||||
struct p9_idpool *p9_idpool_create(void)
|
||||
{
|
||||
struct p9_idpool *p;
|
||||
|
||||
p = kmalloc(sizeof(struct p9_idpool), GFP_KERNEL);
|
||||
if (!p)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
spin_lock_init(&p->lock);
|
||||
idr_init(&p->pool);
|
||||
|
||||
return p;
|
||||
}
|
||||
EXPORT_SYMBOL(p9_idpool_create);
|
||||
|
||||
/**
|
||||
* p9_idpool_destroy - create a new per-connection id pool
|
||||
* @p: idpool to destroy
|
||||
*/
|
||||
|
||||
void p9_idpool_destroy(struct p9_idpool *p)
|
||||
{
|
||||
idr_destroy(&p->pool);
|
||||
kfree(p);
|
||||
}
|
||||
EXPORT_SYMBOL(p9_idpool_destroy);
|
||||
|
||||
/**
|
||||
* p9_idpool_get - allocate numeric id from pool
|
||||
* @p: pool to allocate from
|
||||
*
|
||||
* Bugs: This seems to be an awful generic function, should it be in idr.c with
|
||||
* the lock included in struct idr?
|
||||
*/
|
||||
|
||||
int p9_idpool_get(struct p9_idpool *p)
|
||||
{
|
||||
int i;
|
||||
unsigned long flags;
|
||||
|
||||
idr_preload(GFP_NOFS);
|
||||
spin_lock_irqsave(&p->lock, flags);
|
||||
|
||||
/* no need to store exactly p, we just need something non-null */
|
||||
i = idr_alloc(&p->pool, p, 0, 0, GFP_NOWAIT);
|
||||
|
||||
spin_unlock_irqrestore(&p->lock, flags);
|
||||
idr_preload_end();
|
||||
if (i < 0)
|
||||
return -1;
|
||||
|
||||
p9_debug(P9_DEBUG_MUX, " id %d pool %p\n", i, p);
|
||||
return i;
|
||||
}
|
||||
EXPORT_SYMBOL(p9_idpool_get);
|
||||
|
||||
/**
|
||||
* p9_idpool_put - release numeric id from pool
|
||||
* @id: numeric id which is being released
|
||||
* @p: pool to release id into
|
||||
*
|
||||
* Bugs: This seems to be an awful generic function, should it be in idr.c with
|
||||
* the lock included in struct idr?
|
||||
*/
|
||||
|
||||
void p9_idpool_put(int id, struct p9_idpool *p)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
p9_debug(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);
|
||||
}
|
||||
EXPORT_SYMBOL(p9_idpool_put);
|
||||
|
||||
/**
|
||||
* p9_idpool_check - check if the specified id is available
|
||||
* @id: id to check
|
||||
* @p: pool to check
|
||||
*/
|
||||
|
||||
int p9_idpool_check(int id, struct p9_idpool *p)
|
||||
{
|
||||
return idr_find(&p->pool, id) != NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(p9_idpool_check);
|
Loading…
Reference in New Issue
Block a user