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