Commit 940e3a8d authored by Linus Torvalds's avatar Linus Torvalds

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

Pull v9fs update from Eric Van Hensbergen.

* tag 'for-linus-merge-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs:
  9P: Fix race between p9_write_work() and p9_fd_request()
  9P: Fix race in p9_write_work()
  9P: fix test at the end of p9_write_work()
  9P: Fix race in p9_read_work()
  9p: don't use __getname/__putname for uname/aname
  net/9p: Check errno validity
  fs/9p: avoid debug OOPS when reading a long symlink
parents 12250d84 759f4298
...@@ -184,10 +184,20 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts) ...@@ -184,10 +184,20 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
v9ses->afid = option; v9ses->afid = option;
break; break;
case Opt_uname: case Opt_uname:
match_strlcpy(v9ses->uname, &args[0], PATH_MAX); kfree(v9ses->uname);
v9ses->uname = match_strdup(&args[0]);
if (!v9ses->uname) {
ret = -ENOMEM;
goto free_and_return;
}
break; break;
case Opt_remotename: case Opt_remotename:
match_strlcpy(v9ses->aname, &args[0], PATH_MAX); kfree(v9ses->aname);
v9ses->aname = match_strdup(&args[0]);
if (!v9ses->aname) {
ret = -ENOMEM;
goto free_and_return;
}
break; break;
case Opt_nodevmap: case Opt_nodevmap:
v9ses->nodev = 1; v9ses->nodev = 1;
...@@ -287,21 +297,21 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, ...@@ -287,21 +297,21 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
struct p9_fid *fid; struct p9_fid *fid;
int rc; int rc;
v9ses->uname = __getname(); v9ses->uname = kstrdup(V9FS_DEFUSER, GFP_KERNEL);
if (!v9ses->uname) if (!v9ses->uname)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
v9ses->aname = __getname(); v9ses->aname = kstrdup(V9FS_DEFANAME, GFP_KERNEL);
if (!v9ses->aname) { if (!v9ses->aname) {
__putname(v9ses->uname); kfree(v9ses->uname);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
init_rwsem(&v9ses->rename_sem); init_rwsem(&v9ses->rename_sem);
rc = bdi_setup_and_register(&v9ses->bdi, "9p", BDI_CAP_MAP_COPY); rc = bdi_setup_and_register(&v9ses->bdi, "9p", BDI_CAP_MAP_COPY);
if (rc) { if (rc) {
__putname(v9ses->aname); kfree(v9ses->aname);
__putname(v9ses->uname); kfree(v9ses->uname);
return ERR_PTR(rc); return ERR_PTR(rc);
} }
...@@ -309,8 +319,6 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, ...@@ -309,8 +319,6 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
list_add(&v9ses->slist, &v9fs_sessionlist); list_add(&v9ses->slist, &v9fs_sessionlist);
spin_unlock(&v9fs_sessionlist_lock); spin_unlock(&v9fs_sessionlist_lock);
strcpy(v9ses->uname, V9FS_DEFUSER);
strcpy(v9ses->aname, V9FS_DEFANAME);
v9ses->uid = ~0; v9ses->uid = ~0;
v9ses->dfltuid = V9FS_DEFUID; v9ses->dfltuid = V9FS_DEFUID;
v9ses->dfltgid = V9FS_DEFGID; v9ses->dfltgid = V9FS_DEFGID;
...@@ -412,8 +420,8 @@ void v9fs_session_close(struct v9fs_session_info *v9ses) ...@@ -412,8 +420,8 @@ void v9fs_session_close(struct v9fs_session_info *v9ses)
kfree(v9ses->cachetag); kfree(v9ses->cachetag);
} }
#endif #endif
__putname(v9ses->uname); kfree(v9ses->uname);
__putname(v9ses->aname); kfree(v9ses->aname);
bdi_destroy(&v9ses->bdi); bdi_destroy(&v9ses->bdi);
......
...@@ -1276,12 +1276,12 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) ...@@ -1276,12 +1276,12 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
} }
/* copy extension buffer into buffer */ /* copy extension buffer into buffer */
strncpy(buffer, st->extension, buflen); retval = min(strlen(st->extension)+1, (size_t)buflen);
memcpy(buffer, st->extension, retval);
p9_debug(P9_DEBUG_VFS, "%s -> %s (%s)\n", p9_debug(P9_DEBUG_VFS, "%s -> %s (%.*s)\n",
dentry->d_name.name, st->extension, buffer); dentry->d_name.name, st->extension, buflen, buffer);
retval = strnlen(buffer, buflen);
done: done:
p9stat_free(st); p9stat_free(st);
kfree(st); kfree(st);
......
...@@ -76,6 +76,20 @@ inline int p9_is_proto_dotu(struct p9_client *clnt) ...@@ -76,6 +76,20 @@ inline int p9_is_proto_dotu(struct p9_client *clnt)
} }
EXPORT_SYMBOL(p9_is_proto_dotu); EXPORT_SYMBOL(p9_is_proto_dotu);
/*
* Some error codes are taken directly from the server replies,
* make sure they are valid.
*/
static int safe_errno(int err)
{
if ((err > 0) || (err < -MAX_ERRNO)) {
p9_debug(P9_DEBUG_ERROR, "Invalid error code %d\n", err);
return -EPROTO;
}
return err;
}
/* Interpret mount option for protocol version */ /* Interpret mount option for protocol version */
static int get_protocol_version(char *s) static int get_protocol_version(char *s)
{ {
...@@ -782,7 +796,7 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) ...@@ -782,7 +796,7 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
return req; return req;
reterr: reterr:
p9_free_req(c, req); p9_free_req(c, req);
return ERR_PTR(err); return ERR_PTR(safe_errno(err));
} }
/** /**
...@@ -865,7 +879,7 @@ static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type, ...@@ -865,7 +879,7 @@ static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type,
return req; return req;
reterr: reterr:
p9_free_req(c, req); p9_free_req(c, req);
return ERR_PTR(err); return ERR_PTR(safe_errno(err));
} }
static struct p9_fid *p9_fid_create(struct p9_client *clnt) static struct p9_fid *p9_fid_create(struct p9_client *clnt)
......
...@@ -316,8 +316,7 @@ static void p9_read_work(struct work_struct *work) ...@@ -316,8 +316,7 @@ static void p9_read_work(struct work_struct *work)
m->rsize - m->rpos); m->rsize - m->rpos);
p9_debug(P9_DEBUG_TRANS, "mux %p got %d bytes\n", m, err); p9_debug(P9_DEBUG_TRANS, "mux %p got %d bytes\n", m, err);
if (err == -EAGAIN) { if (err == -EAGAIN) {
clear_bit(Rworksched, &m->wsched); goto end_clear;
return;
} }
if (err <= 0) if (err <= 0)
...@@ -379,19 +378,20 @@ static void p9_read_work(struct work_struct *work) ...@@ -379,19 +378,20 @@ static void p9_read_work(struct work_struct *work)
m->req = NULL; m->req = NULL;
} }
end_clear:
clear_bit(Rworksched, &m->wsched);
if (!list_empty(&m->req_list)) { if (!list_empty(&m->req_list)) {
if (test_and_clear_bit(Rpending, &m->wsched)) if (test_and_clear_bit(Rpending, &m->wsched))
n = POLLIN; n = POLLIN;
else else
n = p9_fd_poll(m->client, NULL); n = p9_fd_poll(m->client, NULL);
if (n & POLLIN) { if ((n & POLLIN) && !test_and_set_bit(Rworksched, &m->wsched)) {
p9_debug(P9_DEBUG_TRANS, "sched read work %p\n", m); p9_debug(P9_DEBUG_TRANS, "sched read work %p\n", m);
schedule_work(&m->rq); schedule_work(&m->rq);
} else }
clear_bit(Rworksched, &m->wsched); }
} else
clear_bit(Rworksched, &m->wsched);
return; return;
error: error:
...@@ -453,12 +453,13 @@ static void p9_write_work(struct work_struct *work) ...@@ -453,12 +453,13 @@ static void p9_write_work(struct work_struct *work)
} }
if (!m->wsize) { if (!m->wsize) {
spin_lock(&m->client->lock);
if (list_empty(&m->unsent_req_list)) { if (list_empty(&m->unsent_req_list)) {
clear_bit(Wworksched, &m->wsched); clear_bit(Wworksched, &m->wsched);
spin_unlock(&m->client->lock);
return; return;
} }
spin_lock(&m->client->lock);
req = list_entry(m->unsent_req_list.next, struct p9_req_t, req = list_entry(m->unsent_req_list.next, struct p9_req_t,
req_list); req_list);
req->status = REQ_STATUS_SENT; req->status = REQ_STATUS_SENT;
...@@ -476,10 +477,9 @@ static void p9_write_work(struct work_struct *work) ...@@ -476,10 +477,9 @@ static void p9_write_work(struct work_struct *work)
clear_bit(Wpending, &m->wsched); clear_bit(Wpending, &m->wsched);
err = p9_fd_write(m->client, m->wbuf + m->wpos, m->wsize - m->wpos); err = p9_fd_write(m->client, m->wbuf + m->wpos, m->wsize - m->wpos);
p9_debug(P9_DEBUG_TRANS, "mux %p sent %d bytes\n", m, err); p9_debug(P9_DEBUG_TRANS, "mux %p sent %d bytes\n", m, err);
if (err == -EAGAIN) { if (err == -EAGAIN)
clear_bit(Wworksched, &m->wsched); goto end_clear;
return;
}
if (err < 0) if (err < 0)
goto error; goto error;
...@@ -492,19 +492,21 @@ static void p9_write_work(struct work_struct *work) ...@@ -492,19 +492,21 @@ static void p9_write_work(struct work_struct *work)
if (m->wpos == m->wsize) if (m->wpos == m->wsize)
m->wpos = m->wsize = 0; m->wpos = m->wsize = 0;
if (m->wsize == 0 && !list_empty(&m->unsent_req_list)) { end_clear:
clear_bit(Wworksched, &m->wsched);
if (m->wsize || !list_empty(&m->unsent_req_list)) {
if (test_and_clear_bit(Wpending, &m->wsched)) if (test_and_clear_bit(Wpending, &m->wsched))
n = POLLOUT; n = POLLOUT;
else else
n = p9_fd_poll(m->client, NULL); n = p9_fd_poll(m->client, NULL);
if (n & POLLOUT) { if ((n & POLLOUT) &&
!test_and_set_bit(Wworksched, &m->wsched)) {
p9_debug(P9_DEBUG_TRANS, "sched write work %p\n", m); p9_debug(P9_DEBUG_TRANS, "sched write work %p\n", m);
schedule_work(&m->wq); schedule_work(&m->wq);
} else }
clear_bit(Wworksched, &m->wsched); }
} else
clear_bit(Wworksched, &m->wsched);
return; return;
......
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