NFS: Fix 2 use after free issues in the I/O code

The writeback code wants to send a commit after processing the pages,
which is why we want to delay releasing the struct path until after
that's done.

Also, the layout code expects that we do not free the inode before
we've put the layout segments in pnfs_writehdr_free() and
pnfs_readhdr_free()

Fixes: 919e3bd9a875 ("NFS: Ensure we commit after writeback is complete")
Fixes: 4714fb51fd03 ("nfs: remove pgio_header refcount, related cleanup")
Cc: stable@vger.kernel.org
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>

+12 -17
-1
fs/nfs/internal.h
··· 251 extern const struct nfs_pageio_ops nfs_pgio_rw_ops; 252 struct nfs_pgio_header *nfs_pgio_header_alloc(const struct nfs_rw_ops *); 253 void nfs_pgio_header_free(struct nfs_pgio_header *); 254 - void nfs_pgio_data_destroy(struct nfs_pgio_header *); 255 int nfs_generic_pgio(struct nfs_pageio_descriptor *, struct nfs_pgio_header *); 256 int nfs_initiate_pgio(struct rpc_clnt *clnt, struct nfs_pgio_header *hdr, 257 struct rpc_cred *cred, const struct nfs_rpc_ops *rpc_ops,
··· 251 extern const struct nfs_pageio_ops nfs_pgio_rw_ops; 252 struct nfs_pgio_header *nfs_pgio_header_alloc(const struct nfs_rw_ops *); 253 void nfs_pgio_header_free(struct nfs_pgio_header *); 254 int nfs_generic_pgio(struct nfs_pageio_descriptor *, struct nfs_pgio_header *); 255 int nfs_initiate_pgio(struct rpc_clnt *clnt, struct nfs_pgio_header *hdr, 256 struct rpc_cred *cred, const struct nfs_rpc_ops *rpc_ops,
+12 -14
fs/nfs/pagelist.c
··· 501 } 502 EXPORT_SYMBOL_GPL(nfs_pgio_header_alloc); 503 504 - /* 505 - * nfs_pgio_header_free - Free a read or write header 506 - * @hdr: The header to free 507 - */ 508 - void nfs_pgio_header_free(struct nfs_pgio_header *hdr) 509 - { 510 - hdr->rw_ops->rw_free_header(hdr); 511 - } 512 - EXPORT_SYMBOL_GPL(nfs_pgio_header_free); 513 - 514 /** 515 * nfs_pgio_data_destroy - make @hdr suitable for reuse 516 * ··· 509 * 510 * @hdr: A header that has had nfs_generic_pgio called 511 */ 512 - void nfs_pgio_data_destroy(struct nfs_pgio_header *hdr) 513 { 514 if (hdr->args.context) 515 put_nfs_open_context(hdr->args.context); 516 if (hdr->page_array.pagevec != hdr->page_array.page_array) 517 kfree(hdr->page_array.pagevec); 518 } 519 - EXPORT_SYMBOL_GPL(nfs_pgio_data_destroy); 520 521 /** 522 * nfs_pgio_rpcsetup - Set up arguments for a pageio call ··· 640 static void nfs_pgio_error(struct nfs_pgio_header *hdr) 641 { 642 set_bit(NFS_IOHDR_REDO, &hdr->flags); 643 - nfs_pgio_data_destroy(hdr); 644 hdr->completion_ops->completion(hdr); 645 } 646 ··· 650 static void nfs_pgio_release(void *calldata) 651 { 652 struct nfs_pgio_header *hdr = calldata; 653 - nfs_pgio_data_destroy(hdr); 654 hdr->completion_ops->completion(hdr); 655 } 656
··· 501 } 502 EXPORT_SYMBOL_GPL(nfs_pgio_header_alloc); 503 504 /** 505 * nfs_pgio_data_destroy - make @hdr suitable for reuse 506 * ··· 519 * 520 * @hdr: A header that has had nfs_generic_pgio called 521 */ 522 + static void nfs_pgio_data_destroy(struct nfs_pgio_header *hdr) 523 { 524 if (hdr->args.context) 525 put_nfs_open_context(hdr->args.context); 526 if (hdr->page_array.pagevec != hdr->page_array.page_array) 527 kfree(hdr->page_array.pagevec); 528 } 529 + 530 + /* 531 + * nfs_pgio_header_free - Free a read or write header 532 + * @hdr: The header to free 533 + */ 534 + void nfs_pgio_header_free(struct nfs_pgio_header *hdr) 535 + { 536 + nfs_pgio_data_destroy(hdr); 537 + hdr->rw_ops->rw_free_header(hdr); 538 + } 539 + EXPORT_SYMBOL_GPL(nfs_pgio_header_free); 540 541 /** 542 * nfs_pgio_rpcsetup - Set up arguments for a pageio call ··· 640 static void nfs_pgio_error(struct nfs_pgio_header *hdr) 641 { 642 set_bit(NFS_IOHDR_REDO, &hdr->flags); 643 hdr->completion_ops->completion(hdr); 644 } 645 ··· 651 static void nfs_pgio_release(void *calldata) 652 { 653 struct nfs_pgio_header *hdr = calldata; 654 hdr->completion_ops->completion(hdr); 655 } 656
-2
fs/nfs/pnfs.c
··· 2233 nfs_pageio_reset_write_mds(desc); 2234 mirror->pg_recoalesce = 1; 2235 } 2236 - nfs_pgio_data_destroy(hdr); 2237 hdr->release(hdr); 2238 } 2239 ··· 2356 nfs_pageio_reset_read_mds(desc); 2357 mirror->pg_recoalesce = 1; 2358 } 2359 - nfs_pgio_data_destroy(hdr); 2360 hdr->release(hdr); 2361 } 2362
··· 2233 nfs_pageio_reset_write_mds(desc); 2234 mirror->pg_recoalesce = 1; 2235 } 2236 hdr->release(hdr); 2237 } 2238 ··· 2357 nfs_pageio_reset_read_mds(desc); 2358 mirror->pg_recoalesce = 1; 2359 } 2360 hdr->release(hdr); 2361 } 2362