The following changes since commit 4cbe5a555fa58a79b6ecbb6c531b8bab0650778d:
Linux 3.6-rc4 (2012-09-01 10:39:58 -0700) are available in the git repository at: git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs.git for-next for you to fetch changes up to 552aad02a283ee88406b102b4d6455eef7127196: 9P: Fix race between p9_write_work() and p9_fd_request() (2012-09-17 14:54:11 -0500) ---------------------------------------------------------------- Jeff Layton (1): 9p: don't use __getname/__putname for uname/aname Jim Meyering (1): fs/9p: avoid debug OOPS when reading a long symlink Simon Derr (5): net/9p: Check errno validity 9P: Fix race in p9_read_work() 9P: fix test at the end of p9_write_work() 9P: Fix race in p9_write_work() 9P: Fix race between p9_write_work() and p9_fd_request() fs/9p/v9fs.c | 30 +++++++++++++++++++----------- fs/9p/vfs_inode.c | 8 ++++---- net/9p/client.c | 18 ++++++++++++++++-- net/9p/trans_fd.c | 38 ++++++++++++++++++++------------------ 4 files changed, 59 insertions(+), 35 deletions(-) Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG/MacGPG2 v2.0.17 (Darwin) Comment: GPGTools - http://gpgtools.org iQIcBAABAgAGBQJQdvxdAAoJEDZk62b0Tg6xru8QAL1I6YH+O6c+sHONQQnifkl/ WciZDUSYx7Pd4Ffy48m6y5J6M2VNFUIzqpIKnm4xAiHUwct/E/+yuyfK2zAe1Jxc nqPxoU2iyFWXc1Hu5HQhrjMXMlqePPuF1kwTYd0vCXXbVgWfbhwYfjoRr3PGuVTD 3SpQrBxIvQj1aWRMyyQTcnqnmTLPFr1kX0TRBgvipSfQETVFR5gCXK8sJUDvU+0S 4kywmb3y31/EpcKdDs7CE1m5kCi6T2mguP5NR4dHtN8YT76IW4urIqyAw6069wQV AMmoqhJP2cJ6kyyh93ltZSgcMIUgfrDj2pIsGT3hILusTh9vBT10Db8iNT2ledy8 W+TxjK0/H0h5rfitHYqD+XnCF4pKFRm5aOOYL8jg02Uh8jU9MzkAIw1/fmXUOZ7O rht+HttJht2QCFniV1C442hbzL0J5mYsGPwpWZ5j4dN7PBIi8SYh+Ik0la4rRa8I m9C04HHvPsc0gRXPAp1+Ptby4FnPS846a9Ffm4xrkNhFl3z916ef67MnoCGu3roM GU9FEOdWhSWJ+52qLcXZwqkrPvlUMOehwnSjlab3BCThPRVK0D7gdTzBN4NDQZWo AzhK5sNRFwEidnYo7gy0g2UsRWRgPP7fiUe/xtlWaBlm0DU1+jZc/uzjEn6/h77R fQfniKFcMRFIeksGts5e =hADE -----END PGP SIGNATURE----- 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
This commit is contained in:
Коммит
940e3a8dd6
30
fs/9p/v9fs.c
30
fs/9p/v9fs.c
|
@ -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,
|
||||||
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,
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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)
|
||||||
}
|
}
|
||||||
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 @@ again:
|
||||||
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,
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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;
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче