Commit 24a52e412ef22989b63c35428652598dc995812c

Authored by Linus Torvalds

Merge tag 'nfs-for-3.20-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs

Pull more NFS client updates from Trond Myklebust:
 "Highlights include:

   - Fix a use-after-free in decode_cb_sequence_args()
   - Fix a compile error when #undef CONFIG_PROC_FS
   - NFSv4.1 backchannel spinlocking issue
   - Cleanups in the NFS unstable write code requested by Linus
   - NFSv4.1 fix issues when the server denies our backchannel request
   - Cleanups in create_session and bind_conn_to_session"

* tag 'nfs-for-3.20-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
  NFSv4.1: Clean up bind_conn_to_session
  NFSv4.1: Always set up a forward channel when binding the session
  NFSv4.1: Don't set up a backchannel if the server didn't agree to do so
  NFSv4.1: Clean up create_session
  pnfs: Refactor the *_layout_mark_request_commit to use pnfs_layout_mark_request_commit
  NFSv4: Kill unused nfs_inode->delegation_state field
  NFS: struct nfs_commit_info.lock must always point to inode->i_lock
  nfs: Can call nfs_clear_page_commit() instead
  nfs: Provide and use helper functions for marking a page as unstable
  SUNRPC: Always manipulate rpc_rqst::rq_bc_pa_list under xprt->bc_pa_lock
  SUNRPC: Fix a compile error when #undef CONFIG_PROC_FS
  NFSv4.1: Convert open-coded array allocation calls to kmalloc_array()
  NFSv4.1: Fix a kfree() of uninitialised pointers in decode_cb_sequence_args

Showing 19 changed files Side-by-side Diff

fs/nfs/callback_proc.c
... ... @@ -427,6 +427,8 @@
427 427 if (clp == NULL)
428 428 goto out;
429 429  
  430 + if (!(clp->cl_session->flags & SESSION4_BACK_CHAN))
  431 + goto out;
430 432 tbl = &clp->cl_session->bc_slot_table;
431 433  
432 434 spin_lock(&tbl->slot_tbl_lock);
fs/nfs/callback_xdr.c
... ... @@ -313,7 +313,7 @@
313 313 goto out;
314 314 }
315 315  
316   - args->devs = kmalloc(n * sizeof(*args->devs), GFP_KERNEL);
  316 + args->devs = kmalloc_array(n, sizeof(*args->devs), GFP_KERNEL);
317 317 if (!args->devs) {
318 318 status = htonl(NFS4ERR_DELAY);
319 319 goto out;
... ... @@ -415,7 +415,7 @@
415 415 rc_list->rcl_nrefcalls * 2 * sizeof(uint32_t));
416 416 if (unlikely(p == NULL))
417 417 goto out;
418   - rc_list->rcl_refcalls = kmalloc(rc_list->rcl_nrefcalls *
  418 + rc_list->rcl_refcalls = kmalloc_array(rc_list->rcl_nrefcalls,
419 419 sizeof(*rc_list->rcl_refcalls),
420 420 GFP_KERNEL);
421 421 if (unlikely(rc_list->rcl_refcalls == NULL))
422 422  
... ... @@ -464,8 +464,10 @@
464 464  
465 465 for (i = 0; i < args->csa_nrclists; i++) {
466 466 status = decode_rc_list(xdr, &args->csa_rclists[i]);
467   - if (status)
  467 + if (status) {
  468 + args->csa_nrclists = i;
468 469 goto out_free;
  470 + }
469 471 }
470 472 }
471 473 status = 0;
... ... @@ -180,7 +180,6 @@
180 180 delegation->cred = get_rpccred(cred);
181 181 clear_bit(NFS_DELEGATION_NEED_RECLAIM,
182 182 &delegation->flags);
183   - NFS_I(inode)->delegation_state = delegation->type;
184 183 spin_unlock(&delegation->lock);
185 184 put_rpccred(oldcred);
186 185 rcu_read_unlock();
... ... @@ -275,7 +274,6 @@
275 274 set_bit(NFS_DELEGATION_RETURNING, &delegation->flags);
276 275 list_del_rcu(&delegation->super_list);
277 276 delegation->inode = NULL;
278   - nfsi->delegation_state = 0;
279 277 rcu_assign_pointer(nfsi->delegation, NULL);
280 278 spin_unlock(&delegation->lock);
281 279 return delegation;
... ... @@ -355,7 +353,6 @@
355 353 &delegation->stateid)) {
356 354 nfs_update_inplace_delegation(old_delegation,
357 355 delegation);
358   - nfsi->delegation_state = old_delegation->type;
359 356 goto out;
360 357 }
361 358 /*
... ... @@ -379,7 +376,6 @@
379 376 goto out;
380 377 }
381 378 list_add_rcu(&delegation->super_list, &server->delegations);
382   - nfsi->delegation_state = delegation->type;
383 379 rcu_assign_pointer(nfsi->delegation, delegation);
384 380 delegation = NULL;
385 381  
... ... @@ -283,7 +283,7 @@
283 283 void nfs_init_cinfo_from_dreq(struct nfs_commit_info *cinfo,
284 284 struct nfs_direct_req *dreq)
285 285 {
286   - cinfo->lock = &dreq->lock;
  286 + cinfo->lock = &dreq->inode->i_lock;
287 287 cinfo->mds = &dreq->mds_cinfo;
288 288 cinfo->ds = &dreq->ds_cinfo;
289 289 cinfo->dreq = dreq;
fs/nfs/filelayout/filelayout.c
... ... @@ -960,52 +960,19 @@
960 960 {
961 961 struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);
962 962 u32 i, j;
963   - struct list_head *list;
964   - struct pnfs_commit_bucket *buckets;
965 963  
966 964 if (fl->commit_through_mds) {
967   - list = &cinfo->mds->list;
968   - spin_lock(cinfo->lock);
969   - goto mds_commit;
970   - }
971   -
972   - /* Note that we are calling nfs4_fl_calc_j_index on each page
973   - * that ends up being committed to a data server. An attractive
974   - * alternative is to add a field to nfs_write_data and nfs_page
975   - * to store the value calculated in filelayout_write_pagelist
976   - * and just use that here.
977   - */
978   - j = nfs4_fl_calc_j_index(lseg, req_offset(req));
979   - i = select_bucket_index(fl, j);
980   - spin_lock(cinfo->lock);
981   - buckets = cinfo->ds->buckets;
982   - list = &buckets[i].written;
983   - if (list_empty(list)) {
984   - /* Non-empty buckets hold a reference on the lseg. That ref
985   - * is normally transferred to the COMMIT call and released
986   - * there. It could also be released if the last req is pulled
987   - * off due to a rewrite, in which case it will be done in
988   - * pnfs_generic_clear_request_commit
  965 + nfs_request_add_commit_list(req, &cinfo->mds->list, cinfo);
  966 + } else {
  967 + /* Note that we are calling nfs4_fl_calc_j_index on each page
  968 + * that ends up being committed to a data server. An attractive
  969 + * alternative is to add a field to nfs_write_data and nfs_page
  970 + * to store the value calculated in filelayout_write_pagelist
  971 + * and just use that here.
989 972 */
990   - buckets[i].wlseg = pnfs_get_lseg(lseg);
991   - }
992   - set_bit(PG_COMMIT_TO_DS, &req->wb_flags);
993   - cinfo->ds->nwritten++;
994   -
995   -mds_commit:
996   - /* nfs_request_add_commit_list(). We need to add req to list without
997   - * dropping cinfo lock.
998   - */
999   - set_bit(PG_CLEAN, &(req)->wb_flags);
1000   - nfs_list_add_request(req, list);
1001   - cinfo->mds->ncommit++;
1002   - spin_unlock(cinfo->lock);
1003   - if (!cinfo->dreq) {
1004   - inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
1005   - inc_bdi_stat(inode_to_bdi(page_file_mapping(req->wb_page)->host),
1006   - BDI_RECLAIMABLE);
1007   - __mark_inode_dirty(req->wb_context->dentry->d_inode,
1008   - I_DIRTY_DATASYNC);
  973 + j = nfs4_fl_calc_j_index(lseg, req_offset(req));
  974 + i = select_bucket_index(fl, j);
  975 + pnfs_layout_mark_request_commit(req, lseg, cinfo, i);
1009 976 }
1010 977 }
1011 978  
fs/nfs/flexfilelayout/flexfilelayout.c
... ... @@ -1332,47 +1332,6 @@
1332 1332 return PNFS_ATTEMPTED;
1333 1333 }
1334 1334  
1335   -static void
1336   -ff_layout_mark_request_commit(struct nfs_page *req,
1337   - struct pnfs_layout_segment *lseg,
1338   - struct nfs_commit_info *cinfo,
1339   - u32 ds_commit_idx)
1340   -{
1341   - struct list_head *list;
1342   - struct pnfs_commit_bucket *buckets;
1343   -
1344   - spin_lock(cinfo->lock);
1345   - buckets = cinfo->ds->buckets;
1346   - list = &buckets[ds_commit_idx].written;
1347   - if (list_empty(list)) {
1348   - /* Non-empty buckets hold a reference on the lseg. That ref
1349   - * is normally transferred to the COMMIT call and released
1350   - * there. It could also be released if the last req is pulled
1351   - * off due to a rewrite, in which case it will be done in
1352   - * pnfs_common_clear_request_commit
1353   - */
1354   - WARN_ON_ONCE(buckets[ds_commit_idx].wlseg != NULL);
1355   - buckets[ds_commit_idx].wlseg = pnfs_get_lseg(lseg);
1356   - }
1357   - set_bit(PG_COMMIT_TO_DS, &req->wb_flags);
1358   - cinfo->ds->nwritten++;
1359   -
1360   - /* nfs_request_add_commit_list(). We need to add req to list without
1361   - * dropping cinfo lock.
1362   - */
1363   - set_bit(PG_CLEAN, &(req)->wb_flags);
1364   - nfs_list_add_request(req, list);
1365   - cinfo->mds->ncommit++;
1366   - spin_unlock(cinfo->lock);
1367   - if (!cinfo->dreq) {
1368   - inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
1369   - inc_bdi_stat(inode_to_bdi(page_file_mapping(req->wb_page)->host),
1370   - BDI_RECLAIMABLE);
1371   - __mark_inode_dirty(req->wb_context->dentry->d_inode,
1372   - I_DIRTY_DATASYNC);
1373   - }
1374   -}
1375   -
1376 1335 static u32 calc_ds_index_from_commit(struct pnfs_layout_segment *lseg, u32 i)
1377 1336 {
1378 1337 return i;
... ... @@ -1540,7 +1499,7 @@
1540 1499 .pg_write_ops = &ff_layout_pg_write_ops,
1541 1500 .get_ds_info = ff_layout_get_ds_info,
1542 1501 .free_deviceid_node = ff_layout_free_deveiceid_node,
1543   - .mark_request_commit = ff_layout_mark_request_commit,
  1502 + .mark_request_commit = pnfs_layout_mark_request_commit,
1544 1503 .clear_request_commit = pnfs_generic_clear_request_commit,
1545 1504 .scan_commit_lists = pnfs_generic_scan_commit_lists,
1546 1505 .recover_commit_reqs = pnfs_generic_recover_commit_reqs,
... ... @@ -1775,7 +1775,6 @@
1775 1775 #if IS_ENABLED(CONFIG_NFS_V4)
1776 1776 INIT_LIST_HEAD(&nfsi->open_states);
1777 1777 nfsi->delegation = NULL;
1778   - nfsi->delegation_state = 0;
1779 1778 init_rwsem(&nfsi->rwsem);
1780 1779 nfsi->layout = NULL;
1781 1780 #endif
... ... @@ -598,6 +598,19 @@
598 598 }
599 599  
600 600 /*
  601 + * Record the page as unstable and mark its inode as dirty.
  602 + */
  603 +static inline
  604 +void nfs_mark_page_unstable(struct page *page)
  605 +{
  606 + struct inode *inode = page_file_mapping(page)->host;
  607 +
  608 + inc_zone_page_state(page, NR_UNSTABLE_NFS);
  609 + inc_bdi_stat(inode_to_bdi(inode), BDI_RECLAIMABLE);
  610 + __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
  611 +}
  612 +
  613 +/*
601 614 * Determine the number of bytes of data the page contains
602 615 */
603 616 static inline
... ... @@ -6648,47 +6648,47 @@
6648 6648 int nfs4_proc_bind_conn_to_session(struct nfs_client *clp, struct rpc_cred *cred)
6649 6649 {
6650 6650 int status;
  6651 + struct nfs41_bind_conn_to_session_args args = {
  6652 + .client = clp,
  6653 + .dir = NFS4_CDFC4_FORE_OR_BOTH,
  6654 + };
6651 6655 struct nfs41_bind_conn_to_session_res res;
6652 6656 struct rpc_message msg = {
6653 6657 .rpc_proc =
6654 6658 &nfs4_procedures[NFSPROC4_CLNT_BIND_CONN_TO_SESSION],
6655   - .rpc_argp = clp,
  6659 + .rpc_argp = &args,
6656 6660 .rpc_resp = &res,
6657 6661 .rpc_cred = cred,
6658 6662 };
6659 6663  
6660 6664 dprintk("--> %s\n", __func__);
6661 6665  
6662   - res.session = kzalloc(sizeof(struct nfs4_session), GFP_NOFS);
6663   - if (unlikely(res.session == NULL)) {
6664   - status = -ENOMEM;
6665   - goto out;
6666   - }
  6666 + nfs4_copy_sessionid(&args.sessionid, &clp->cl_session->sess_id);
  6667 + if (!(clp->cl_session->flags & SESSION4_BACK_CHAN))
  6668 + args.dir = NFS4_CDFC4_FORE;
6667 6669  
6668 6670 status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
6669 6671 trace_nfs4_bind_conn_to_session(clp, status);
6670 6672 if (status == 0) {
6671   - if (memcmp(res.session->sess_id.data,
  6673 + if (memcmp(res.sessionid.data,
6672 6674 clp->cl_session->sess_id.data, NFS4_MAX_SESSIONID_LEN)) {
6673 6675 dprintk("NFS: %s: Session ID mismatch\n", __func__);
6674 6676 status = -EIO;
6675   - goto out_session;
  6677 + goto out;
6676 6678 }
6677   - if (res.dir != NFS4_CDFS4_BOTH) {
  6679 + if ((res.dir & args.dir) != res.dir || res.dir == 0) {
6678 6680 dprintk("NFS: %s: Unexpected direction from server\n",
6679 6681 __func__);
6680 6682 status = -EIO;
6681   - goto out_session;
  6683 + goto out;
6682 6684 }
6683   - if (res.use_conn_in_rdma_mode) {
  6685 + if (res.use_conn_in_rdma_mode != args.use_conn_in_rdma_mode) {
6684 6686 dprintk("NFS: %s: Server returned RDMA mode = true\n",
6685 6687 __func__);
6686 6688 status = -EIO;
6687   - goto out_session;
  6689 + goto out;
6688 6690 }
6689 6691 }
6690   -out_session:
6691   - kfree(res.session);
6692 6692 out:
6693 6693 dprintk("<-- %s status= %d\n", __func__, status);
6694 6694 return status;
6695 6695  
... ... @@ -7166,10 +7166,11 @@
7166 7166 args->bc_attrs.max_reqs);
7167 7167 }
7168 7168  
7169   -static int nfs4_verify_fore_channel_attrs(struct nfs41_create_session_args *args, struct nfs4_session *session)
  7169 +static int nfs4_verify_fore_channel_attrs(struct nfs41_create_session_args *args,
  7170 + struct nfs41_create_session_res *res)
7170 7171 {
7171 7172 struct nfs4_channel_attrs *sent = &args->fc_attrs;
7172   - struct nfs4_channel_attrs *rcvd = &session->fc_attrs;
  7173 + struct nfs4_channel_attrs *rcvd = &res->fc_attrs;
7173 7174  
7174 7175 if (rcvd->max_resp_sz > sent->max_resp_sz)
7175 7176 return -EINVAL;
7176 7177  
7177 7178  
... ... @@ -7188,11 +7189,14 @@
7188 7189 return 0;
7189 7190 }
7190 7191  
7191   -static int nfs4_verify_back_channel_attrs(struct nfs41_create_session_args *args, struct nfs4_session *session)
  7192 +static int nfs4_verify_back_channel_attrs(struct nfs41_create_session_args *args,
  7193 + struct nfs41_create_session_res *res)
7192 7194 {
7193 7195 struct nfs4_channel_attrs *sent = &args->bc_attrs;
7194   - struct nfs4_channel_attrs *rcvd = &session->bc_attrs;
  7196 + struct nfs4_channel_attrs *rcvd = &res->bc_attrs;
7195 7197  
  7198 + if (!(res->flags & SESSION4_BACK_CHAN))
  7199 + goto out;
7196 7200 if (rcvd->max_rqst_sz > sent->max_rqst_sz)
7197 7201 return -EINVAL;
7198 7202 if (rcvd->max_resp_sz < sent->max_resp_sz)
7199 7203  
7200 7204  
7201 7205  
7202 7206  
7203 7207  
7204 7208  
... ... @@ -7204,31 +7208,44 @@
7204 7208 return -EINVAL;
7205 7209 if (rcvd->max_reqs != sent->max_reqs)
7206 7210 return -EINVAL;
  7211 +out:
7207 7212 return 0;
7208 7213 }
7209 7214  
7210 7215 static int nfs4_verify_channel_attrs(struct nfs41_create_session_args *args,
7211   - struct nfs4_session *session)
  7216 + struct nfs41_create_session_res *res)
7212 7217 {
7213 7218 int ret;
7214 7219  
7215   - ret = nfs4_verify_fore_channel_attrs(args, session);
  7220 + ret = nfs4_verify_fore_channel_attrs(args, res);
7216 7221 if (ret)
7217 7222 return ret;
7218   - return nfs4_verify_back_channel_attrs(args, session);
  7223 + return nfs4_verify_back_channel_attrs(args, res);
7219 7224 }
7220 7225  
  7226 +static void nfs4_update_session(struct nfs4_session *session,
  7227 + struct nfs41_create_session_res *res)
  7228 +{
  7229 + nfs4_copy_sessionid(&session->sess_id, &res->sessionid);
  7230 + session->flags = res->flags;
  7231 + memcpy(&session->fc_attrs, &res->fc_attrs, sizeof(session->fc_attrs));
  7232 + if (res->flags & SESSION4_BACK_CHAN)
  7233 + memcpy(&session->bc_attrs, &res->bc_attrs,
  7234 + sizeof(session->bc_attrs));
  7235 +}
  7236 +
7221 7237 static int _nfs4_proc_create_session(struct nfs_client *clp,
7222 7238 struct rpc_cred *cred)
7223 7239 {
7224 7240 struct nfs4_session *session = clp->cl_session;
7225 7241 struct nfs41_create_session_args args = {
7226 7242 .client = clp,
  7243 + .clientid = clp->cl_clientid,
  7244 + .seqid = clp->cl_seqid,
7227 7245 .cb_program = NFS4_CALLBACK,
7228 7246 };
7229   - struct nfs41_create_session_res res = {
7230   - .client = clp,
7231   - };
  7247 + struct nfs41_create_session_res res;
  7248 +
7232 7249 struct rpc_message msg = {
7233 7250 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE_SESSION],
7234 7251 .rpc_argp = &args,
7235 7252  
7236 7253  
... ... @@ -7245,11 +7262,15 @@
7245 7262  
7246 7263 if (!status) {
7247 7264 /* Verify the session's negotiated channel_attrs values */
7248   - status = nfs4_verify_channel_attrs(&args, session);
  7265 + status = nfs4_verify_channel_attrs(&args, &res);
7249 7266 /* Increment the clientid slot sequence id */
7250   - clp->cl_seqid++;
  7267 + if (clp->cl_seqid == res.seqid)
  7268 + clp->cl_seqid++;
  7269 + if (status)
  7270 + goto out;
  7271 + nfs4_update_session(session, &res);
7251 7272 }
7252   -
  7273 +out:
7253 7274 return status;
7254 7275 }
7255 7276  
fs/nfs/nfs4session.c
... ... @@ -450,7 +450,7 @@
450 450 tbl = &ses->fc_slot_table;
451 451 tbl->session = ses;
452 452 status = nfs4_realloc_slot_table(tbl, ses->fc_attrs.max_reqs, 1);
453   - if (status) /* -ENOMEM */
  453 + if (status || !(ses->flags & SESSION4_BACK_CHAN)) /* -ENOMEM */
454 454 return status;
455 455 /* Back channel */
456 456 tbl = &ses->bc_slot_table;
fs/nfs/nfs4session.h
... ... @@ -118,6 +118,12 @@
118 118 return 0;
119 119 }
120 120  
  121 +static inline void nfs4_copy_sessionid(struct nfs4_sessionid *dst,
  122 + const struct nfs4_sessionid *src)
  123 +{
  124 + memcpy(dst->data, src->data, NFS4_MAX_SESSIONID_LEN);
  125 +}
  126 +
121 127 #ifdef CONFIG_CRC32
122 128 /*
123 129 * nfs_session_id_hash - calculate the crc32 hash for the session id
... ... @@ -1715,17 +1715,17 @@
1715 1715 #if defined(CONFIG_NFS_V4_1)
1716 1716 /* NFSv4.1 operations */
1717 1717 static void encode_bind_conn_to_session(struct xdr_stream *xdr,
1718   - struct nfs4_session *session,
  1718 + struct nfs41_bind_conn_to_session_args *args,
1719 1719 struct compound_hdr *hdr)
1720 1720 {
1721 1721 __be32 *p;
1722 1722  
1723 1723 encode_op_hdr(xdr, OP_BIND_CONN_TO_SESSION,
1724 1724 decode_bind_conn_to_session_maxsz, hdr);
1725   - encode_opaque_fixed(xdr, session->sess_id.data, NFS4_MAX_SESSIONID_LEN);
  1725 + encode_opaque_fixed(xdr, args->sessionid.data, NFS4_MAX_SESSIONID_LEN);
1726 1726 p = xdr_reserve_space(xdr, 8);
1727   - *p++ = cpu_to_be32(NFS4_CDFC4_BACK_OR_BOTH);
1728   - *p = 0; /* use_conn_in_rdma_mode = False */
  1727 + *p++ = cpu_to_be32(args->dir);
  1728 + *p = (args->use_conn_in_rdma_mode) ? cpu_to_be32(1) : cpu_to_be32(0);
1729 1729 }
1730 1730  
1731 1731 static void encode_op_map(struct xdr_stream *xdr, struct nfs4_op_map *op_map)
... ... @@ -1806,8 +1806,8 @@
1806 1806  
1807 1807 encode_op_hdr(xdr, OP_CREATE_SESSION, decode_create_session_maxsz, hdr);
1808 1808 p = reserve_space(xdr, 16 + 2*28 + 20 + clnt->cl_nodelen + 12);
1809   - p = xdr_encode_hyper(p, clp->cl_clientid);
1810   - *p++ = cpu_to_be32(clp->cl_seqid); /*Sequence id */
  1809 + p = xdr_encode_hyper(p, args->clientid);
  1810 + *p++ = cpu_to_be32(args->seqid); /*Sequence id */
1811 1811 *p++ = cpu_to_be32(args->flags); /*flags */
1812 1812  
1813 1813 /* Fore Channel */
1814 1814  
1815 1815  
... ... @@ -2734,14 +2734,14 @@
2734 2734 */
2735 2735 static void nfs4_xdr_enc_bind_conn_to_session(struct rpc_rqst *req,
2736 2736 struct xdr_stream *xdr,
2737   - struct nfs_client *clp)
  2737 + struct nfs41_bind_conn_to_session_args *args)
2738 2738 {
2739 2739 struct compound_hdr hdr = {
2740   - .minorversion = clp->cl_mvops->minor_version,
  2740 + .minorversion = args->client->cl_mvops->minor_version,
2741 2741 };
2742 2742  
2743 2743 encode_compound_hdr(xdr, req, &hdr);
2744   - encode_bind_conn_to_session(xdr, clp->cl_session, &hdr);
  2744 + encode_bind_conn_to_session(xdr, args, &hdr);
2745 2745 encode_nops(&hdr);
2746 2746 }
2747 2747  
... ... @@ -5613,7 +5613,7 @@
5613 5613  
5614 5614 status = decode_op_hdr(xdr, OP_BIND_CONN_TO_SESSION);
5615 5615 if (!status)
5616   - status = decode_sessionid(xdr, &res->session->sess_id);
  5616 + status = decode_sessionid(xdr, &res->sessionid);
5617 5617 if (unlikely(status))
5618 5618 return status;
5619 5619  
5620 5620  
... ... @@ -5641,12 +5641,10 @@
5641 5641 {
5642 5642 __be32 *p;
5643 5643 int status;
5644   - struct nfs_client *clp = res->client;
5645   - struct nfs4_session *session = clp->cl_session;
5646 5644  
5647 5645 status = decode_op_hdr(xdr, OP_CREATE_SESSION);
5648 5646 if (!status)
5649   - status = decode_sessionid(xdr, &session->sess_id);
  5647 + status = decode_sessionid(xdr, &res->sessionid);
5650 5648 if (unlikely(status))
5651 5649 return status;
5652 5650  
5653 5651  
5654 5652  
... ... @@ -5654,13 +5652,13 @@
5654 5652 p = xdr_inline_decode(xdr, 8);
5655 5653 if (unlikely(!p))
5656 5654 goto out_overflow;
5657   - clp->cl_seqid = be32_to_cpup(p++);
5658   - session->flags = be32_to_cpup(p);
  5655 + res->seqid = be32_to_cpup(p++);
  5656 + res->flags = be32_to_cpup(p);
5659 5657  
5660 5658 /* Channel attributes */
5661   - status = decode_chan_attrs(xdr, &session->fc_attrs);
  5659 + status = decode_chan_attrs(xdr, &res->fc_attrs);
5662 5660 if (!status)
5663   - status = decode_chan_attrs(xdr, &session->bc_attrs);
  5661 + status = decode_chan_attrs(xdr, &res->bc_attrs);
5664 5662 return status;
5665 5663 out_overflow:
5666 5664 print_overflow_msg(__func__, xdr);
... ... @@ -344,6 +344,10 @@
344 344 struct nfs4_pnfs_ds_addr *nfs4_decode_mp_ds_addr(struct net *net,
345 345 struct xdr_stream *xdr,
346 346 gfp_t gfp_flags);
  347 +void pnfs_layout_mark_request_commit(struct nfs_page *req,
  348 + struct pnfs_layout_segment *lseg,
  349 + struct nfs_commit_info *cinfo,
  350 + u32 ds_commit_idx);
347 351  
348 352 static inline bool nfs_have_layout(struct inode *inode)
349 353 {
... ... @@ -838,4 +838,34 @@
838 838 return NULL;
839 839 }
840 840 EXPORT_SYMBOL_GPL(nfs4_decode_mp_ds_addr);
  841 +
  842 +void
  843 +pnfs_layout_mark_request_commit(struct nfs_page *req,
  844 + struct pnfs_layout_segment *lseg,
  845 + struct nfs_commit_info *cinfo,
  846 + u32 ds_commit_idx)
  847 +{
  848 + struct list_head *list;
  849 + struct pnfs_commit_bucket *buckets;
  850 +
  851 + spin_lock(cinfo->lock);
  852 + buckets = cinfo->ds->buckets;
  853 + list = &buckets[ds_commit_idx].written;
  854 + if (list_empty(list)) {
  855 + /* Non-empty buckets hold a reference on the lseg. That ref
  856 + * is normally transferred to the COMMIT call and released
  857 + * there. It could also be released if the last req is pulled
  858 + * off due to a rewrite, in which case it will be done in
  859 + * pnfs_common_clear_request_commit
  860 + */
  861 + WARN_ON_ONCE(buckets[ds_commit_idx].wlseg != NULL);
  862 + buckets[ds_commit_idx].wlseg = pnfs_get_lseg(lseg);
  863 + }
  864 + set_bit(PG_COMMIT_TO_DS, &req->wb_flags);
  865 + cinfo->ds->nwritten++;
  866 + spin_unlock(cinfo->lock);
  867 +
  868 + nfs_request_add_commit_list(req, list, cinfo);
  869 +}
  870 +EXPORT_SYMBOL_GPL(pnfs_layout_mark_request_commit);
... ... @@ -789,13 +789,8 @@
789 789 nfs_list_add_request(req, dst);
790 790 cinfo->mds->ncommit++;
791 791 spin_unlock(cinfo->lock);
792   - if (!cinfo->dreq) {
793   - inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
794   - inc_bdi_stat(inode_to_bdi(page_file_mapping(req->wb_page)->host),
795   - BDI_RECLAIMABLE);
796   - __mark_inode_dirty(req->wb_context->dentry->d_inode,
797   - I_DIRTY_DATASYNC);
798   - }
  792 + if (!cinfo->dreq)
  793 + nfs_mark_page_unstable(req->wb_page);
799 794 }
800 795 EXPORT_SYMBOL_GPL(nfs_request_add_commit_list);
801 796  
... ... @@ -1605,11 +1600,8 @@
1605 1600 req = nfs_list_entry(page_list->next);
1606 1601 nfs_list_remove_request(req);
1607 1602 nfs_mark_request_commit(req, lseg, cinfo, ds_commit_idx);
1608   - if (!cinfo->dreq) {
1609   - dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
1610   - dec_bdi_stat(inode_to_bdi(page_file_mapping(req->wb_page)->host),
1611   - BDI_RECLAIMABLE);
1612   - }
  1603 + if (!cinfo->dreq)
  1604 + nfs_clear_page_commit(req->wb_page);
1613 1605 nfs_unlock_and_release_request(req);
1614 1606 }
1615 1607 }
include/linux/nfs_fs.h
... ... @@ -180,7 +180,6 @@
180 180 /* NFSv4 state */
181 181 struct list_head open_states;
182 182 struct nfs_delegation __rcu *delegation;
183   - fmode_t delegation_state;
184 183 struct rw_semaphore rwsem;
185 184  
186 185 /* pNFS layout information */
include/linux/nfs_xdr.h
... ... @@ -1167,8 +1167,15 @@
1167 1167 struct nfstime4 date;
1168 1168 };
1169 1169  
  1170 +struct nfs41_bind_conn_to_session_args {
  1171 + struct nfs_client *client;
  1172 + struct nfs4_sessionid sessionid;
  1173 + u32 dir;
  1174 + bool use_conn_in_rdma_mode;
  1175 +};
  1176 +
1170 1177 struct nfs41_bind_conn_to_session_res {
1171   - struct nfs4_session *session;
  1178 + struct nfs4_sessionid sessionid;
1172 1179 u32 dir;
1173 1180 bool use_conn_in_rdma_mode;
1174 1181 };
... ... @@ -1185,6 +1192,8 @@
1185 1192  
1186 1193 struct nfs41_create_session_args {
1187 1194 struct nfs_client *client;
  1195 + u64 clientid;
  1196 + uint32_t seqid;
1188 1197 uint32_t flags;
1189 1198 uint32_t cb_program;
1190 1199 struct nfs4_channel_attrs fc_attrs; /* Fore Channel */
... ... @@ -1192,7 +1201,11 @@
1192 1201 };
1193 1202  
1194 1203 struct nfs41_create_session_res {
1195   - struct nfs_client *client;
  1204 + struct nfs4_sessionid sessionid;
  1205 + uint32_t seqid;
  1206 + uint32_t flags;
  1207 + struct nfs4_channel_attrs fc_attrs; /* Fore Channel */
  1208 + struct nfs4_channel_attrs bc_attrs; /* Back Channel */
1196 1209 };
1197 1210  
1198 1211 struct nfs41_reclaim_complete_args {
... ... @@ -1351,7 +1364,7 @@
1351 1364 };
1352 1365  
1353 1366 struct nfs_commit_info {
1354   - spinlock_t *lock;
  1367 + spinlock_t *lock; /* inode->i_lock */
1355 1368 struct nfs_mds_commit_info *mds;
1356 1369 struct pnfs_ds_commit_info *ds;
1357 1370 struct nfs_direct_req *dreq; /* O_DIRECT request */
include/linux/sunrpc/metrics.h
... ... @@ -89,8 +89,11 @@
89 89 static inline struct rpc_iostats *rpc_alloc_iostats(struct rpc_clnt *clnt) { return NULL; }
90 90 static inline void rpc_count_iostats(const struct rpc_task *task,
91 91 struct rpc_iostats *stats) {}
92   -static inline void rpc_count_iostats_metrics(const struct rpc_task *,
93   - struct rpc_iostats *) {}
  92 +static inline void rpc_count_iostats_metrics(const struct rpc_task *task,
  93 + struct rpc_iostats *stats)
  94 +{
  95 +}
  96 +
94 97 static inline void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt) {}
95 98 static inline void rpc_free_iostats(struct rpc_iostats *stats) {}
96 99  
net/sunrpc/backchannel_rqst.c
... ... @@ -309,12 +309,15 @@
309 309 struct rpc_xprt *xprt = req->rq_xprt;
310 310 struct svc_serv *bc_serv = xprt->bc_serv;
311 311  
  312 + spin_lock(&xprt->bc_pa_lock);
  313 + list_del(&req->rq_bc_pa_list);
  314 + spin_unlock(&xprt->bc_pa_lock);
  315 +
312 316 req->rq_private_buf.len = copied;
313 317 set_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state);
314 318  
315 319 dprintk("RPC: add callback request to list\n");
316 320 spin_lock(&bc_serv->sv_cb_lock);
317   - list_del(&req->rq_bc_pa_list);
318 321 list_add(&req->rq_bc_list, &bc_serv->sv_cb_list);
319 322 wake_up(&bc_serv->sv_cb_waitq);
320 323 spin_unlock(&bc_serv->sv_cb_lock);