Commit 7a528159 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs:
  9p: fix put_data error handling
  9p: use an IS_ERR test rather than a NULL test
  9p: introduce missing kfree
  9p-trans_fd: fix and clean up module init/exit paths
  9p-trans_fd: don't do fs segment mangling in p9_fd_poll()
  9p-trans_fd: clean up p9_conn_create()
  9p-trans_fd: fix trans_fd::p9_conn_destroy()
  9p: implement proper trans module refcounting and unregistration
parents fb478da5 16ec4700
...@@ -626,8 +626,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -626,8 +626,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
return NULL; return NULL;
error: error:
if (fid) p9_client_clunk(fid);
p9_client_clunk(fid);
return ERR_PTR(result); return ERR_PTR(result);
} }
......
...@@ -596,4 +596,5 @@ int p9_idpool_check(int id, struct p9_idpool *p); ...@@ -596,4 +596,5 @@ int p9_idpool_check(int id, struct p9_idpool *p);
int p9_error_init(void); int p9_error_init(void);
int p9_errstr2errno(char *, int); int p9_errstr2errno(char *, int);
int p9_trans_fd_init(void); int p9_trans_fd_init(void);
void p9_trans_fd_exit(void);
#endif /* NET_9P_H */ #endif /* NET_9P_H */
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
#ifndef NET_9P_TRANSPORT_H #ifndef NET_9P_TRANSPORT_H
#define NET_9P_TRANSPORT_H #define NET_9P_TRANSPORT_H
#include <linux/module.h>
/** /**
* enum p9_trans_status - different states of underlying transports * enum p9_trans_status - different states of underlying transports
* @Connected: transport is connected and healthy * @Connected: transport is connected and healthy
...@@ -91,9 +93,12 @@ struct p9_trans_module { ...@@ -91,9 +93,12 @@ struct p9_trans_module {
int maxsize; /* max message size of transport */ int maxsize; /* max message size of transport */
int def; /* this transport should be default */ int def; /* this transport should be default */
struct p9_trans * (*create)(const char *, char *, int, unsigned char); struct p9_trans * (*create)(const char *, char *, int, unsigned char);
struct module *owner;
}; };
void v9fs_register_trans(struct p9_trans_module *m); void v9fs_register_trans(struct p9_trans_module *m);
struct p9_trans_module *v9fs_match_trans(const substring_t *name); void v9fs_unregister_trans(struct p9_trans_module *m);
struct p9_trans_module *v9fs_default_trans(void); struct p9_trans_module *v9fs_get_trans_by_name(const substring_t *name);
struct p9_trans_module *v9fs_get_default_trans(void);
void v9fs_put_trans(struct p9_trans_module *m);
#endif /* NET_9P_TRANSPORT_H */ #endif /* NET_9P_TRANSPORT_H */
...@@ -75,7 +75,6 @@ static int parse_opts(char *opts, struct p9_client *clnt) ...@@ -75,7 +75,6 @@ static int parse_opts(char *opts, struct p9_client *clnt)
int option; int option;
int ret = 0; int ret = 0;
clnt->trans_mod = v9fs_default_trans();
clnt->dotu = 1; clnt->dotu = 1;
clnt->msize = 8192; clnt->msize = 8192;
...@@ -108,7 +107,7 @@ static int parse_opts(char *opts, struct p9_client *clnt) ...@@ -108,7 +107,7 @@ static int parse_opts(char *opts, struct p9_client *clnt)
clnt->msize = option; clnt->msize = option;
break; break;
case Opt_trans: case Opt_trans:
clnt->trans_mod = v9fs_match_trans(&args[0]); clnt->trans_mod = v9fs_get_trans_by_name(&args[0]);
break; break;
case Opt_legacy: case Opt_legacy:
clnt->dotu = 0; clnt->dotu = 0;
...@@ -117,6 +116,10 @@ static int parse_opts(char *opts, struct p9_client *clnt) ...@@ -117,6 +116,10 @@ static int parse_opts(char *opts, struct p9_client *clnt)
continue; continue;
} }
} }
if (!clnt->trans_mod)
clnt->trans_mod = v9fs_get_default_trans();
kfree(options); kfree(options);
return ret; return ret;
} }
...@@ -150,6 +153,7 @@ struct p9_client *p9_client_create(const char *dev_name, char *options) ...@@ -150,6 +153,7 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
if (!clnt) if (!clnt)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
clnt->trans_mod = NULL;
clnt->trans = NULL; clnt->trans = NULL;
spin_lock_init(&clnt->lock); spin_lock_init(&clnt->lock);
INIT_LIST_HEAD(&clnt->fidlist); INIT_LIST_HEAD(&clnt->fidlist);
...@@ -235,6 +239,8 @@ void p9_client_destroy(struct p9_client *clnt) ...@@ -235,6 +239,8 @@ void p9_client_destroy(struct p9_client *clnt)
clnt->trans = NULL; clnt->trans = NULL;
} }
v9fs_put_trans(clnt->trans_mod);
list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist) list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist)
p9_fid_destroy(fid); p9_fid_destroy(fid);
......
...@@ -451,8 +451,10 @@ p9_put_data(struct cbuf *bufp, const char *data, int count, ...@@ -451,8 +451,10 @@ p9_put_data(struct cbuf *bufp, const char *data, int count,
unsigned char **pdata) unsigned char **pdata)
{ {
*pdata = buf_alloc(bufp, count); *pdata = buf_alloc(bufp, count);
if (*pdata == NULL)
return -ENOMEM;
memmove(*pdata, data, count); memmove(*pdata, data, count);
return count; return 0;
} }
static int static int
...@@ -460,6 +462,8 @@ p9_put_user_data(struct cbuf *bufp, const char __user *data, int count, ...@@ -460,6 +462,8 @@ p9_put_user_data(struct cbuf *bufp, const char __user *data, int count,
unsigned char **pdata) unsigned char **pdata)
{ {
*pdata = buf_alloc(bufp, count); *pdata = buf_alloc(bufp, count);
if (*pdata == NULL)
return -ENOMEM;
return copy_from_user(*pdata, data, count); return copy_from_user(*pdata, data, count);
} }
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/parser.h> #include <linux/parser.h>
#include <net/9p/transport.h> #include <net/9p/transport.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/spinlock.h>
#ifdef CONFIG_NET_9P_DEBUG #ifdef CONFIG_NET_9P_DEBUG
unsigned int p9_debug_level = 0; /* feature-rific global debug level */ unsigned int p9_debug_level = 0; /* feature-rific global debug level */
...@@ -44,8 +45,8 @@ MODULE_PARM_DESC(debug, "9P debugging level"); ...@@ -44,8 +45,8 @@ MODULE_PARM_DESC(debug, "9P debugging level");
* *
*/ */
static DEFINE_SPINLOCK(v9fs_trans_lock);
static LIST_HEAD(v9fs_trans_list); static LIST_HEAD(v9fs_trans_list);
static struct p9_trans_module *v9fs_default_transport;
/** /**
* v9fs_register_trans - register a new transport with 9p * v9fs_register_trans - register a new transport with 9p
...@@ -54,48 +55,87 @@ static struct p9_trans_module *v9fs_default_transport; ...@@ -54,48 +55,87 @@ static struct p9_trans_module *v9fs_default_transport;
*/ */
void v9fs_register_trans(struct p9_trans_module *m) void v9fs_register_trans(struct p9_trans_module *m)
{ {
spin_lock(&v9fs_trans_lock);
list_add_tail(&m->list, &v9fs_trans_list); list_add_tail(&m->list, &v9fs_trans_list);
if (m->def) spin_unlock(&v9fs_trans_lock);
v9fs_default_transport = m;
} }
EXPORT_SYMBOL(v9fs_register_trans); EXPORT_SYMBOL(v9fs_register_trans);
/** /**
* v9fs_match_trans - match transport versus registered transports * v9fs_unregister_trans - unregister a 9p transport
* @m: the transport to remove
*
*/
void v9fs_unregister_trans(struct p9_trans_module *m)
{
spin_lock(&v9fs_trans_lock);
list_del_init(&m->list);
spin_unlock(&v9fs_trans_lock);
}
EXPORT_SYMBOL(v9fs_unregister_trans);
/**
* v9fs_get_trans_by_name - get transport with the matching name
* @name: string identifying transport * @name: string identifying transport
* *
*/ */
struct p9_trans_module *v9fs_match_trans(const substring_t *name) struct p9_trans_module *v9fs_get_trans_by_name(const substring_t *name)
{ {
struct list_head *p; struct p9_trans_module *t, *found = NULL;
struct p9_trans_module *t = NULL;
spin_lock(&v9fs_trans_lock);
list_for_each(p, &v9fs_trans_list) {
t = list_entry(p, struct p9_trans_module, list); list_for_each_entry(t, &v9fs_trans_list, list)
if (strncmp(t->name, name->from, name->to-name->from) == 0) if (strncmp(t->name, name->from, name->to-name->from) == 0 &&
return t; try_module_get(t->owner)) {
} found = t;
return NULL; break;
}
spin_unlock(&v9fs_trans_lock);
return found;
} }
EXPORT_SYMBOL(v9fs_match_trans); EXPORT_SYMBOL(v9fs_get_trans_by_name);
/** /**
* v9fs_default_trans - returns pointer to default transport * v9fs_get_default_trans - get the default transport
* *
*/ */
struct p9_trans_module *v9fs_default_trans(void) struct p9_trans_module *v9fs_get_default_trans(void)
{ {
if (v9fs_default_transport) struct p9_trans_module *t, *found = NULL;
return v9fs_default_transport;
else if (!list_empty(&v9fs_trans_list)) spin_lock(&v9fs_trans_lock);
return list_first_entry(&v9fs_trans_list,
struct p9_trans_module, list); list_for_each_entry(t, &v9fs_trans_list, list)
else if (t->def && try_module_get(t->owner)) {
return NULL; found = t;
break;
}
if (!found)
list_for_each_entry(t, &v9fs_trans_list, list)
if (try_module_get(t->owner)) {
found = t;
break;
}
spin_unlock(&v9fs_trans_lock);
return found;
} }
EXPORT_SYMBOL(v9fs_default_trans); EXPORT_SYMBOL(v9fs_get_default_trans);
/**
* v9fs_put_trans - put trans
* @m: transport to put
*
*/
void v9fs_put_trans(struct p9_trans_module *m)
{
if (m)
module_put(m->owner);
}
/** /**
* v9fs_init - Initialize module * v9fs_init - Initialize module
...@@ -120,6 +160,8 @@ static int __init init_p9(void) ...@@ -120,6 +160,8 @@ static int __init init_p9(void)
static void __exit exit_p9(void) static void __exit exit_p9(void)
{ {
printk(KERN_INFO "Unloading 9P2000 support\n"); printk(KERN_INFO "Unloading 9P2000 support\n");
p9_trans_fd_exit();
} }
module_init(init_p9) module_init(init_p9)
......
...@@ -151,7 +151,6 @@ struct p9_mux_poll_task { ...@@ -151,7 +151,6 @@ struct p9_mux_poll_task {
* @trans: reference to transport instance for this connection * @trans: reference to transport instance for this connection
* @tagpool: id accounting for transactions * @tagpool: id accounting for transactions
* @err: error state * @err: error state
* @equeue: event wait_q (?)
* @req_list: accounting for requests which have been sent * @req_list: accounting for requests which have been sent
* @unsent_req_list: accounting for requests that haven't been sent * @unsent_req_list: accounting for requests that haven't been sent
* @rcall: current response &p9_fcall structure * @rcall: current response &p9_fcall structure
...@@ -178,7 +177,6 @@ struct p9_conn { ...@@ -178,7 +177,6 @@ struct p9_conn {
struct p9_trans *trans; struct p9_trans *trans;
struct p9_idpool *tagpool; struct p9_idpool *tagpool;
int err; int err;
wait_queue_head_t equeue;
struct list_head req_list; struct list_head req_list;
struct list_head unsent_req_list; struct list_head unsent_req_list;
struct p9_fcall *rcall; struct p9_fcall *rcall;
...@@ -240,22 +238,6 @@ static int p9_conn_rpcnb(struct p9_conn *m, struct p9_fcall *tc, ...@@ -240,22 +238,6 @@ static int p9_conn_rpcnb(struct p9_conn *m, struct p9_fcall *tc,
static void p9_conn_cancel(struct p9_conn *m, int err); static void p9_conn_cancel(struct p9_conn *m, int err);
static int p9_mux_global_init(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++)
p9_mux_poll_tasks[i].task = NULL;
p9_mux_wq = create_workqueue("v9fs");
if (!p9_mux_wq) {
printk(KERN_WARNING "v9fs: mux: creating workqueue failed\n");
return -ENOMEM;
}
return 0;
}
static u16 p9_mux_get_tag(struct p9_conn *m) static u16 p9_mux_get_tag(struct p9_conn *m)
{ {
int tag; int tag;
...@@ -409,11 +391,11 @@ static void p9_mux_poll_stop(struct p9_conn *m) ...@@ -409,11 +391,11 @@ static void p9_mux_poll_stop(struct p9_conn *m)
static struct p9_conn *p9_conn_create(struct p9_trans *trans) static struct p9_conn *p9_conn_create(struct p9_trans *trans)
{ {
int i, n; int i, n;
struct p9_conn *m, *mtmp; struct p9_conn *m;
P9_DPRINTK(P9_DEBUG_MUX, "transport %p msize %d\n", trans, P9_DPRINTK(P9_DEBUG_MUX, "transport %p msize %d\n", trans,
trans->msize); trans->msize);
m = kmalloc(sizeof(struct p9_conn), GFP_KERNEL); m = kzalloc(sizeof(struct p9_conn), GFP_KERNEL);
if (!m) if (!m)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -424,25 +406,14 @@ static struct p9_conn *p9_conn_create(struct p9_trans *trans) ...@@ -424,25 +406,14 @@ static struct p9_conn *p9_conn_create(struct p9_trans *trans)
m->trans = trans; m->trans = trans;
m->tagpool = p9_idpool_create(); m->tagpool = p9_idpool_create();
if (IS_ERR(m->tagpool)) { if (IS_ERR(m->tagpool)) {
mtmp = ERR_PTR(-ENOMEM);
kfree(m); kfree(m);
return mtmp; return ERR_PTR(-ENOMEM);
} }
m->err = 0;
init_waitqueue_head(&m->equeue);
INIT_LIST_HEAD(&m->req_list); INIT_LIST_HEAD(&m->req_list);
INIT_LIST_HEAD(&m->unsent_req_list); INIT_LIST_HEAD(&m->unsent_req_list);
m->rcall = NULL;
m->rpos = 0;
m->rbuf = NULL;
m->wpos = m->wsize = 0;
m->wbuf = NULL;
INIT_WORK(&m->rq, p9_read_work); INIT_WORK(&m->rq, p9_read_work);
INIT_WORK(&m->wq, p9_write_work); INIT_WORK(&m->wq, p9_write_work);
m->wsched = 0;
memset(&m->poll_waddr, 0, sizeof(m->poll_waddr));
m->poll_task = NULL;
n = p9_mux_poll_start(m); n = p9_mux_poll_start(m);
if (n) { if (n) {
kfree(m); kfree(m);
...@@ -463,10 +434,8 @@ static struct p9_conn *p9_conn_create(struct p9_trans *trans) ...@@ -463,10 +434,8 @@ static struct p9_conn *p9_conn_create(struct p9_trans *trans)
for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) { for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) {
if (IS_ERR(m->poll_waddr[i])) { if (IS_ERR(m->poll_waddr[i])) {
p9_mux_poll_stop(m); p9_mux_poll_stop(m);
mtmp = (void *)m->poll_waddr; /* the error code */
kfree(m); kfree(m);
m = mtmp; return (void *)m->poll_waddr; /* the error code */
break;
} }
} }
...@@ -483,18 +452,13 @@ static void p9_conn_destroy(struct p9_conn *m) ...@@ -483,18 +452,13 @@ 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_MUX, "mux %p prev %p next %p\n", m,
m->mux_list.prev, m->mux_list.next); m->mux_list.prev, m->mux_list.next);
p9_conn_cancel(m, -ECONNRESET);
if (!list_empty(&m->req_list)) {
/* wait until all processes waiting on this session exit */
P9_DPRINTK(P9_DEBUG_MUX,
"mux %p waiting for empty request queue\n", m);
wait_event_timeout(m->equeue, (list_empty(&m->req_list)), 5000);
P9_DPRINTK(P9_DEBUG_MUX, "mux %p request queue empty: %d\n", m,
list_empty(&m->req_list));
}
p9_mux_poll_stop(m); p9_mux_poll_stop(m);
cancel_work_sync(&m->rq);
cancel_work_sync(&m->wq);
p9_conn_cancel(m, -ECONNRESET);
m->trans = NULL; m->trans = NULL;
p9_idpool_destroy(m->tagpool); p9_idpool_destroy(m->tagpool);
kfree(m); kfree(m);
...@@ -840,8 +804,6 @@ static void p9_read_work(struct work_struct *work) ...@@ -840,8 +804,6 @@ static void p9_read_work(struct work_struct *work)
(*req->cb) (req, req->cba); (*req->cb) (req, req->cba);
else else
kfree(req->rcall); kfree(req->rcall);
wake_up(&m->equeue);
} }
} else { } else {
if (err >= 0 && rcall->id != P9_RFLUSH) if (err >= 0 && rcall->id != P9_RFLUSH)
...@@ -908,8 +870,10 @@ static struct p9_req *p9_send_request(struct p9_conn *m, ...@@ -908,8 +870,10 @@ static struct p9_req *p9_send_request(struct p9_conn *m,
else else
n = p9_mux_get_tag(m); n = p9_mux_get_tag(m);
if (n < 0) if (n < 0) {
kfree(req);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
}
p9_set_tag(tc, n); p9_set_tag(tc, n);
...@@ -984,8 +948,6 @@ static void p9_mux_flush_cb(struct p9_req *freq, void *a) ...@@ -984,8 +948,6 @@ static void p9_mux_flush_cb(struct p9_req *freq, void *a)
(*req->cb) (req, req->cba); (*req->cb) (req, req->cba);
else else
kfree(req->rcall); kfree(req->rcall);
wake_up(&m->equeue);
} }
kfree(freq->tcall); kfree(freq->tcall);
...@@ -1191,8 +1153,6 @@ void p9_conn_cancel(struct p9_conn *m, int err) ...@@ -1191,8 +1153,6 @@ void p9_conn_cancel(struct p9_conn *m, int err)
else else
kfree(req->rcall); kfree(req->rcall);
} }
wake_up(&m->equeue);
} }
/** /**
...@@ -1370,7 +1330,6 @@ p9_fd_poll(struct p9_trans *trans, struct poll_table_struct *pt) ...@@ -1370,7 +1330,6 @@ p9_fd_poll(struct p9_trans *trans, struct poll_table_struct *pt)
{ {
int ret, n; int ret, n;
struct p9_trans_fd *ts = NULL; struct p9_trans_fd *ts = NULL;
mm_segment_t oldfs;
if (trans && trans->status == Connected) if (trans && trans->status == Connected)
ts = trans->priv; ts = trans->priv;
...@@ -1384,24 +1343,17 @@ p9_fd_poll(struct p9_trans *trans, struct poll_table_struct *pt) ...@@ -1384,24 +1343,17 @@ p9_fd_poll(struct p9_trans *trans, struct poll_table_struct *pt)
if (!ts->wr->f_op || !ts->wr->f_op->poll) if (!ts->wr->f_op || !ts->wr->f_op->poll)
return -EIO; return -EIO;
oldfs = get_fs();
set_fs(get_ds());
ret = ts->rd->f_op->poll(ts->rd, pt); ret = ts->rd->f_op->poll(ts->rd, pt);
if (ret < 0) if (ret < 0)
goto end; return ret;
if (ts->rd != ts->wr) { if (ts->rd != ts->wr) {
n = ts->wr->f_op->poll(ts->wr, pt); n = ts->wr->f_op->poll(ts->wr, pt);
if (n < 0) { if (n < 0)
ret = n; return n;
goto end;
}
ret = (ret & ~POLLOUT) | (n & ~POLLIN); ret = (ret & ~POLLOUT) | (n & ~POLLIN);
} }
end:
set_fs(oldfs);
return ret; return ret;
} }
...@@ -1629,6 +1581,7 @@ static struct p9_trans_module p9_tcp_trans = { ...@@ -1629,6 +1581,7 @@ static struct p9_trans_module p9_tcp_trans = {
.maxsize = MAX_SOCK_BUF, .maxsize = MAX_SOCK_BUF,
.def = 1, .def = 1,
.create = p9_trans_create_tcp, .create = p9_trans_create_tcp,
.owner = THIS_MODULE,
}; };
static struct p9_trans_module p9_unix_trans = { static struct p9_trans_module p9_unix_trans = {
...@@ -1636,6 +1589,7 @@ static struct p9_trans_module p9_unix_trans = { ...@@ -1636,6 +1589,7 @@ static struct p9_trans_module p9_unix_trans = {
.maxsize = MAX_SOCK_BUF, .maxsize = MAX_SOCK_BUF,
.def = 0, .def = 0,
.create = p9_trans_create_unix, .create = p9_trans_create_unix,
.owner = THIS_MODULE,
}; };
static struct p9_trans_module p9_fd_trans = { static struct p9_trans_module p9_fd_trans = {
...@@ -1643,14 +1597,20 @@ static struct p9_trans_module p9_fd_trans = { ...@@ -1643,14 +1597,20 @@ static struct p9_trans_module p9_fd_trans = {
.maxsize = MAX_SOCK_BUF, .maxsize = MAX_SOCK_BUF,
.def = 0, .def = 0,
.create = p9_trans_create_fd, .create = p9_trans_create_fd,
.owner = THIS_MODULE,
}; };
int p9_trans_fd_init(void) int p9_trans_fd_init(void)
{ {
int ret = p9_mux_global_init(); int i;
if (ret) {
printk(KERN_WARNING "9p: starting mux failed\n"); for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++)
return ret; p9_mux_poll_tasks[i].task = NULL;
p9_mux_wq = create_workqueue("v9fs");
if (!p9_mux_wq) {
printk(KERN_WARNING "v9fs: mux: creating workqueue failed\n");
return -ENOMEM;
} }
v9fs_register_trans(&p9_tcp_trans); v9fs_register_trans(&p9_tcp_trans);
...@@ -1659,4 +1619,12 @@ int p9_trans_fd_init(void) ...@@ -1659,4 +1619,12 @@ int p9_trans_fd_init(void)
return 0; return 0;
} }
EXPORT_SYMBOL(p9_trans_fd_init);
void p9_trans_fd_exit(void)
{
v9fs_unregister_trans(&p9_tcp_trans);
v9fs_unregister_trans(&p9_unix_trans);
v9fs_unregister_trans(&p9_fd_trans);
destroy_workqueue(p9_mux_wq);
}
...@@ -528,6 +528,7 @@ static struct p9_trans_module p9_virtio_trans = { ...@@ -528,6 +528,7 @@ static struct p9_trans_module p9_virtio_trans = {
.create = p9_virtio_create, .create = p9_virtio_create,
.maxsize = PAGE_SIZE*16, .maxsize = PAGE_SIZE*16,
.def = 0, .def = 0,
.owner = THIS_MODULE,
}; };
/* The standard init function */ /* The standard init function */
...@@ -545,6 +546,7 @@ static int __init p9_virtio_init(void) ...@@ -545,6 +546,7 @@ static int __init p9_virtio_init(void)
static void __exit p9_virtio_cleanup(void) static void __exit p9_virtio_cleanup(void)
{ {
unregister_virtio_driver(&p9_virtio_drv); unregister_virtio_driver(&p9_virtio_drv);
v9fs_unregister_trans(&p9_virtio_trans);
} }
module_init(p9_virtio_init); module_init(p9_virtio_init);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment