Commit 8841b5f0 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'nfs-for-4.11-2' of git://git.linux-nfs.org/projects/anna/linux-nfs

Pull NFS client fixes from Anna Schumaker:
 "We have a handful of stable fixes to fix kernel warnings and other
  bugs that have been around for a while. We've also found a few other
  reference counting bugs and memory leaks since the initial 4.11 pull.

  Stable Bugfixes:
   - Fix decrementing nrequests in NFS v4.2 COPY to fix kernel warnings
   - Prevent a double free in async nfs4_exchange_id()
   - Squelch a kbuild sparse complaint for xprtrdma

  Other Bugfixes:
   - Fix a typo (NFS_ATTR_FATTR_GROUP_NAME) that causes a memory leak
   - Fix a reference leak that causes kernel warnings
   - Make nfs4_cb_sv_ops static to fix a sparse warning
   - Respect a server's max size in CREATE_SESSION
   - Handle errors from nfs4_pnfs_ds_connect
   - Flexfiles layout shouldn't mark devices as unavailable"

* tag 'nfs-for-4.11-2' of git://git.linux-nfs.org/projects/anna/linux-nfs:
  pNFS/flexfiles: never nfs4_mark_deviceid_unavailable
  pNFS: return status from nfs4_pnfs_ds_connect
  NFSv4.1 respect server's max size in CREATE_SESSION
  NFS prevent double free in async nfs4_exchange_id
  nfs: make nfs4_cb_sv_ops static
  xprtrdma: Squelch kbuild sparse complaint
  NFS: fix the fault nrequests decreasing for nfs_inode COPY
  NFSv4: fix a reference leak caused WARNING messages
  nfs4: fix a typo of NFS_ATTR_FATTR_GROUP_NAME
parents eab60d4e da066f3f
...@@ -232,12 +232,12 @@ static struct svc_serv_ops nfs41_cb_sv_ops = { ...@@ -232,12 +232,12 @@ static struct svc_serv_ops nfs41_cb_sv_ops = {
.svo_module = THIS_MODULE, .svo_module = THIS_MODULE,
}; };
struct svc_serv_ops *nfs4_cb_sv_ops[] = { static struct svc_serv_ops *nfs4_cb_sv_ops[] = {
[0] = &nfs40_cb_sv_ops, [0] = &nfs40_cb_sv_ops,
[1] = &nfs41_cb_sv_ops, [1] = &nfs41_cb_sv_ops,
}; };
#else #else
struct svc_serv_ops *nfs4_cb_sv_ops[] = { static struct svc_serv_ops *nfs4_cb_sv_ops[] = {
[0] = &nfs40_cb_sv_ops, [0] = &nfs40_cb_sv_ops,
[1] = NULL, [1] = NULL,
}; };
......
...@@ -325,10 +325,33 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat ...@@ -325,10 +325,33 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat
return NULL; return NULL;
} }
static bool nfs_client_init_is_complete(const struct nfs_client *clp) /*
* Return true if @clp is done initializing, false if still working on it.
*
* Use nfs_client_init_status to check if it was successful.
*/
bool nfs_client_init_is_complete(const struct nfs_client *clp)
{ {
return clp->cl_cons_state <= NFS_CS_READY; return clp->cl_cons_state <= NFS_CS_READY;
} }
EXPORT_SYMBOL_GPL(nfs_client_init_is_complete);
/*
* Return 0 if @clp was successfully initialized, -errno otherwise.
*
* This must be called *after* nfs_client_init_is_complete() returns true,
* otherwise it will pop WARN_ON_ONCE and return -EINVAL
*/
int nfs_client_init_status(const struct nfs_client *clp)
{
/* called without checking nfs_client_init_is_complete */
if (clp->cl_cons_state > NFS_CS_READY) {
WARN_ON_ONCE(1);
return -EINVAL;
}
return clp->cl_cons_state;
}
EXPORT_SYMBOL_GPL(nfs_client_init_status);
int nfs_wait_client_init_complete(const struct nfs_client *clp) int nfs_wait_client_init_complete(const struct nfs_client *clp)
{ {
......
...@@ -266,6 +266,7 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx) ...@@ -266,6 +266,7 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg); struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg);
struct nfs4_pnfs_ds *ret = ds; struct nfs4_pnfs_ds *ret = ds;
struct nfs_server *s = NFS_SERVER(lseg->pls_layout->plh_inode); struct nfs_server *s = NFS_SERVER(lseg->pls_layout->plh_inode);
int status;
if (ds == NULL) { if (ds == NULL) {
printk(KERN_ERR "NFS: %s: No data server for offset index %d\n", printk(KERN_ERR "NFS: %s: No data server for offset index %d\n",
...@@ -277,9 +278,14 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx) ...@@ -277,9 +278,14 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
if (ds->ds_clp) if (ds->ds_clp)
goto out_test_devid; goto out_test_devid;
nfs4_pnfs_ds_connect(s, ds, devid, dataserver_timeo, status = nfs4_pnfs_ds_connect(s, ds, devid, dataserver_timeo,
dataserver_retrans, 4, dataserver_retrans, 4,
s->nfs_client->cl_minorversion); s->nfs_client->cl_minorversion);
if (status) {
nfs4_mark_deviceid_unavailable(devid);
ret = NULL;
goto out;
}
out_test_devid: out_test_devid:
if (ret->ds_clp == NULL || if (ret->ds_clp == NULL ||
......
...@@ -175,7 +175,19 @@ ff_layout_no_read_on_rw(struct pnfs_layout_segment *lseg) ...@@ -175,7 +175,19 @@ ff_layout_no_read_on_rw(struct pnfs_layout_segment *lseg)
static inline bool static inline bool
ff_layout_test_devid_unavailable(struct nfs4_deviceid_node *node) ff_layout_test_devid_unavailable(struct nfs4_deviceid_node *node)
{ {
return nfs4_test_deviceid_unavailable(node); /*
* Flexfiles should never mark a DS unavailable, but if it does
* print a (ratelimited) warning as this can affect performance.
*/
if (nfs4_test_deviceid_unavailable(node)) {
u32 *p = (u32 *)node->deviceid.data;
pr_warn_ratelimited("NFS: flexfiles layout referencing an "
"unavailable device [%x%x%x%x]\n",
p[0], p[1], p[2], p[3]);
return true;
}
return false;
} }
static inline int static inline int
......
...@@ -384,6 +384,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx, ...@@ -384,6 +384,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx,
struct inode *ino = lseg->pls_layout->plh_inode; struct inode *ino = lseg->pls_layout->plh_inode;
struct nfs_server *s = NFS_SERVER(ino); struct nfs_server *s = NFS_SERVER(ino);
unsigned int max_payload; unsigned int max_payload;
int status;
if (!ff_layout_mirror_valid(lseg, mirror, true)) { if (!ff_layout_mirror_valid(lseg, mirror, true)) {
pr_err_ratelimited("NFS: %s: No data server for offset index %d\n", pr_err_ratelimited("NFS: %s: No data server for offset index %d\n",
...@@ -404,7 +405,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx, ...@@ -404,7 +405,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx,
/* FIXME: For now we assume the server sent only one version of NFS /* FIXME: For now we assume the server sent only one version of NFS
* to use for the DS. * to use for the DS.
*/ */
nfs4_pnfs_ds_connect(s, ds, devid, dataserver_timeo, status = nfs4_pnfs_ds_connect(s, ds, devid, dataserver_timeo,
dataserver_retrans, dataserver_retrans,
mirror->mirror_ds->ds_versions[0].version, mirror->mirror_ds->ds_versions[0].version,
mirror->mirror_ds->ds_versions[0].minor_version); mirror->mirror_ds->ds_versions[0].minor_version);
...@@ -420,11 +421,11 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx, ...@@ -420,11 +421,11 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx,
mirror->mirror_ds->ds_versions[0].wsize = max_payload; mirror->mirror_ds->ds_versions[0].wsize = max_payload;
goto out; goto out;
} }
out_fail:
ff_layout_track_ds_error(FF_LAYOUT_FROM_HDR(lseg->pls_layout), ff_layout_track_ds_error(FF_LAYOUT_FROM_HDR(lseg->pls_layout),
mirror, lseg->pls_range.offset, mirror, lseg->pls_range.offset,
lseg->pls_range.length, NFS4ERR_NXIO, lseg->pls_range.length, NFS4ERR_NXIO,
OP_ILLEGAL, GFP_NOIO); OP_ILLEGAL, GFP_NOIO);
out_fail:
if (fail_return || !ff_layout_has_available_ds(lseg)) if (fail_return || !ff_layout_has_available_ds(lseg))
pnfs_error_mark_layout_for_return(ino, lseg); pnfs_error_mark_layout_for_return(ino, lseg);
ds = NULL; ds = NULL;
......
...@@ -186,6 +186,8 @@ extern struct nfs_server *nfs_clone_server(struct nfs_server *, ...@@ -186,6 +186,8 @@ extern struct nfs_server *nfs_clone_server(struct nfs_server *,
struct nfs_fh *, struct nfs_fh *,
struct nfs_fattr *, struct nfs_fattr *,
rpc_authflavor_t); rpc_authflavor_t);
extern bool nfs_client_init_is_complete(const struct nfs_client *clp);
extern int nfs_client_init_status(const struct nfs_client *clp);
extern int nfs_wait_client_init_complete(const struct nfs_client *clp); extern int nfs_wait_client_init_complete(const struct nfs_client *clp);
extern void nfs_mark_client_ready(struct nfs_client *clp, int state); extern void nfs_mark_client_ready(struct nfs_client *clp, int state);
extern struct nfs_client *nfs4_set_ds_client(struct nfs_server *mds_srv, extern struct nfs_client *nfs4_set_ds_client(struct nfs_server *mds_srv,
......
...@@ -1023,9 +1023,9 @@ static void nfs4_session_set_rwsize(struct nfs_server *server) ...@@ -1023,9 +1023,9 @@ static void nfs4_session_set_rwsize(struct nfs_server *server)
server_resp_sz = sess->fc_attrs.max_resp_sz - nfs41_maxread_overhead; server_resp_sz = sess->fc_attrs.max_resp_sz - nfs41_maxread_overhead;
server_rqst_sz = sess->fc_attrs.max_rqst_sz - nfs41_maxwrite_overhead; server_rqst_sz = sess->fc_attrs.max_rqst_sz - nfs41_maxwrite_overhead;
if (server->rsize > server_resp_sz) if (!server->rsize || server->rsize > server_resp_sz)
server->rsize = server_resp_sz; server->rsize = server_resp_sz;
if (server->wsize > server_rqst_sz) if (!server->wsize || server->wsize > server_rqst_sz)
server->wsize = server_rqst_sz; server->wsize = server_rqst_sz;
#endif /* CONFIG_NFS_V4_1 */ #endif /* CONFIG_NFS_V4_1 */
} }
......
...@@ -2258,8 +2258,6 @@ static int nfs4_opendata_access(struct rpc_cred *cred, ...@@ -2258,8 +2258,6 @@ static int nfs4_opendata_access(struct rpc_cred *cred,
if ((mask & ~cache.mask & (MAY_READ | MAY_EXEC)) == 0) if ((mask & ~cache.mask & (MAY_READ | MAY_EXEC)) == 0)
return 0; return 0;
/* even though OPEN succeeded, access is denied. Close the file */
nfs4_close_state(state, fmode);
return -EACCES; return -EACCES;
} }
...@@ -7427,11 +7425,11 @@ static void nfs4_exchange_id_release(void *data) ...@@ -7427,11 +7425,11 @@ static void nfs4_exchange_id_release(void *data)
struct nfs41_exchange_id_data *cdata = struct nfs41_exchange_id_data *cdata =
(struct nfs41_exchange_id_data *)data; (struct nfs41_exchange_id_data *)data;
nfs_put_client(cdata->args.client);
if (cdata->xprt) { if (cdata->xprt) {
xprt_put(cdata->xprt); xprt_put(cdata->xprt);
rpc_clnt_xprt_switch_put(cdata->args.client->cl_rpcclient); rpc_clnt_xprt_switch_put(cdata->args.client->cl_rpcclient);
} }
nfs_put_client(cdata->args.client);
kfree(cdata->res.impl_id); kfree(cdata->res.impl_id);
kfree(cdata->res.server_scope); kfree(cdata->res.server_scope);
kfree(cdata->res.server_owner); kfree(cdata->res.server_owner);
...@@ -7538,10 +7536,8 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred, ...@@ -7538,10 +7536,8 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
task_setup_data.callback_data = calldata; task_setup_data.callback_data = calldata;
task = rpc_run_task(&task_setup_data); task = rpc_run_task(&task_setup_data);
if (IS_ERR(task)) { if (IS_ERR(task))
status = PTR_ERR(task); return PTR_ERR(task);
goto out_impl_id;
}
if (!xprt) { if (!xprt) {
status = rpc_wait_for_completion_task(task); status = rpc_wait_for_completion_task(task);
...@@ -7569,6 +7565,7 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred, ...@@ -7569,6 +7565,7 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
kfree(calldata->res.server_owner); kfree(calldata->res.server_owner);
out_calldata: out_calldata:
kfree(calldata); kfree(calldata);
nfs_put_client(clp);
goto out; goto out;
} }
......
...@@ -3942,7 +3942,7 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, ...@@ -3942,7 +3942,7 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap,
if (len <= 0) if (len <= 0)
goto out; goto out;
dprintk("%s: name=%s\n", __func__, group_name->data); dprintk("%s: name=%s\n", __func__, group_name->data);
return NFS_ATTR_FATTR_OWNER_NAME; return NFS_ATTR_FATTR_GROUP_NAME;
} else { } else {
len = xdr_stream_decode_opaque_inline(xdr, (void **)&p, len = xdr_stream_decode_opaque_inline(xdr, (void **)&p,
XDR_MAX_NETOBJ); XDR_MAX_NETOBJ);
......
...@@ -367,7 +367,7 @@ void nfs4_pnfs_ds_put(struct nfs4_pnfs_ds *ds); ...@@ -367,7 +367,7 @@ void nfs4_pnfs_ds_put(struct nfs4_pnfs_ds *ds);
struct nfs4_pnfs_ds *nfs4_pnfs_ds_add(struct list_head *dsaddrs, struct nfs4_pnfs_ds *nfs4_pnfs_ds_add(struct list_head *dsaddrs,
gfp_t gfp_flags); gfp_t gfp_flags);
void nfs4_pnfs_v3_ds_connect_unload(void); void nfs4_pnfs_v3_ds_connect_unload(void);
void nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds, int nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds,
struct nfs4_deviceid_node *devid, unsigned int timeo, struct nfs4_deviceid_node *devid, unsigned int timeo,
unsigned int retrans, u32 version, u32 minor_version); unsigned int retrans, u32 version, u32 minor_version);
struct nfs4_pnfs_ds_addr *nfs4_decode_mp_ds_addr(struct net *net, struct nfs4_pnfs_ds_addr *nfs4_decode_mp_ds_addr(struct net *net,
......
...@@ -745,15 +745,17 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv, ...@@ -745,15 +745,17 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv,
/* /*
* Create an rpc connection to the nfs4_pnfs_ds data server. * Create an rpc connection to the nfs4_pnfs_ds data server.
* Currently only supports IPv4 and IPv6 addresses. * Currently only supports IPv4 and IPv6 addresses.
* If connection fails, make devid unavailable. * If connection fails, make devid unavailable and return a -errno.
*/ */
void nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds, int nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds,
struct nfs4_deviceid_node *devid, unsigned int timeo, struct nfs4_deviceid_node *devid, unsigned int timeo,
unsigned int retrans, u32 version, u32 minor_version) unsigned int retrans, u32 version, u32 minor_version)
{ {
if (test_and_set_bit(NFS4DS_CONNECTING, &ds->ds_state) == 0) { int err;
int err = 0;
again:
err = 0;
if (test_and_set_bit(NFS4DS_CONNECTING, &ds->ds_state) == 0) {
if (version == 3) { if (version == 3) {
err = _nfs4_pnfs_v3_ds_connect(mds_srv, ds, timeo, err = _nfs4_pnfs_v3_ds_connect(mds_srv, ds, timeo,
retrans); retrans);
...@@ -766,12 +768,29 @@ void nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds, ...@@ -766,12 +768,29 @@ void nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds,
err = -EPROTONOSUPPORT; err = -EPROTONOSUPPORT;
} }
if (err)
nfs4_mark_deviceid_unavailable(devid);
nfs4_clear_ds_conn_bit(ds); nfs4_clear_ds_conn_bit(ds);
} else { } else {
nfs4_wait_ds_connect(ds); nfs4_wait_ds_connect(ds);
/* what was waited on didn't connect AND didn't mark unavail */
if (!ds->ds_clp && !nfs4_test_deviceid_unavailable(devid))
goto again;
} }
/*
* At this point the ds->ds_clp should be ready, but it might have
* hit an error.
*/
if (!err) {
if (!ds->ds_clp || !nfs_client_init_is_complete(ds->ds_clp)) {
WARN_ON_ONCE(ds->ds_clp ||
!nfs4_test_deviceid_unavailable(devid));
return -EINVAL;
}
err = nfs_client_init_status(ds->ds_clp);
}
return err;
} }
EXPORT_SYMBOL_GPL(nfs4_pnfs_ds_connect); EXPORT_SYMBOL_GPL(nfs4_pnfs_ds_connect);
......
...@@ -1784,7 +1784,8 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data) ...@@ -1784,7 +1784,8 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data)
(long long)req_offset(req)); (long long)req_offset(req));
if (status < 0) { if (status < 0) {
nfs_context_set_write_error(req->wb_context, status); nfs_context_set_write_error(req->wb_context, status);
nfs_inode_remove_request(req); if (req->wb_page)
nfs_inode_remove_request(req);
dprintk_cont(", error = %d\n", status); dprintk_cont(", error = %d\n", status);
goto next; goto next;
} }
...@@ -1793,7 +1794,8 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data) ...@@ -1793,7 +1794,8 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data)
* returned by the server against all stored verfs. */ * returned by the server against all stored verfs. */
if (!nfs_write_verifier_cmp(&req->wb_verf, &data->verf.verifier)) { if (!nfs_write_verifier_cmp(&req->wb_verf, &data->verf.verifier)) {
/* We have a match */ /* We have a match */
nfs_inode_remove_request(req); if (req->wb_page)
nfs_inode_remove_request(req);
dprintk_cont(" OK\n"); dprintk_cont(" OK\n");
goto next; goto next;
} }
......
...@@ -503,7 +503,8 @@ rpcrdma_ep_create(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia, ...@@ -503,7 +503,8 @@ rpcrdma_ep_create(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia,
struct ib_cq *sendcq, *recvcq; struct ib_cq *sendcq, *recvcq;
int rc; int rc;
max_sge = min(ia->ri_device->attrs.max_sge, RPCRDMA_MAX_SEND_SGES); max_sge = min_t(unsigned int, ia->ri_device->attrs.max_sge,
RPCRDMA_MAX_SEND_SGES);
if (max_sge < RPCRDMA_MIN_SEND_SGES) { if (max_sge < RPCRDMA_MIN_SEND_SGES) {
pr_warn("rpcrdma: HCA provides only %d send SGEs\n", max_sge); pr_warn("rpcrdma: HCA provides only %d send SGEs\n", max_sge);
return -ENOMEM; return -ENOMEM;
......
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