NFS: Fix an O_DIRECT Oops...

We can't call nfs_readdata_release()/nfs_writedata_release() without
first initialising and referencing args.context. Doing so inside
nfs_direct_read_schedule_segment()/nfs_direct_write_schedule_segment()
causes an Oops.

We should rather be calling nfs_readdata_free()/nfs_writedata_free() in
those cases.

Looking at the O_DIRECT code, the "struct nfs_direct_req" is already
referencing the nfs_open_context for us. Since the readdata and writedata
structures carry a reference to that, we can simplify things by getting rid
of the extra nfs_open_context references, so that we can replace all
instances of nfs_readdata_release()/nfs_writedata_release().

Reported-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Tested-by: Catalin Marinas <catalin.marinas@arm.com>
Cc: stable@kernel.org
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by Trond Myklebust and committed by Linus Torvalds 1ae88b2e 7cb7beb3

+16 -21
+10 -10
fs/nfs/direct.c
··· 255 256 if (put_dreq(dreq)) 257 nfs_direct_complete(dreq); 258 - nfs_readdata_release(calldata); 259 } 260 261 static const struct rpc_call_ops nfs_read_direct_ops = { ··· 314 data->npages, 1, 0, data->pagevec, NULL); 315 up_read(&current->mm->mmap_sem); 316 if (result < 0) { 317 - nfs_readdata_release(data); 318 break; 319 } 320 if ((unsigned)result < data->npages) { 321 bytes = result * PAGE_SIZE; 322 if (bytes <= pgbase) { 323 nfs_direct_release_pages(data->pagevec, result); 324 - nfs_readdata_release(data); 325 break; 326 } 327 bytes -= pgbase; ··· 334 data->inode = inode; 335 data->cred = msg.rpc_cred; 336 data->args.fh = NFS_FH(inode); 337 - data->args.context = get_nfs_open_context(ctx); 338 data->args.offset = pos; 339 data->args.pgbase = pgbase; 340 data->args.pages = data->pagevec; ··· 441 struct nfs_write_data *data = list_entry(dreq->rewrite_list.next, struct nfs_write_data, pages); 442 list_del(&data->pages); 443 nfs_direct_release_pages(data->pagevec, data->npages); 444 - nfs_writedata_release(data); 445 } 446 } 447 ··· 534 535 dprintk("NFS: %5u commit returned %d\n", data->task.tk_pid, status); 536 nfs_direct_write_complete(dreq, data->inode); 537 - nfs_commitdata_release(calldata); 538 } 539 540 static const struct rpc_call_ops nfs_commit_direct_ops = { ··· 570 data->args.fh = NFS_FH(data->inode); 571 data->args.offset = 0; 572 data->args.count = 0; 573 - data->args.context = get_nfs_open_context(dreq->ctx); 574 data->res.count = 0; 575 data->res.fattr = &data->fattr; 576 data->res.verf = &data->verf; ··· 734 data->npages, 0, 0, data->pagevec, NULL); 735 up_read(&current->mm->mmap_sem); 736 if (result < 0) { 737 - nfs_writedata_release(data); 738 break; 739 } 740 if ((unsigned)result < data->npages) { 741 bytes = result * PAGE_SIZE; 742 if (bytes <= pgbase) { 743 nfs_direct_release_pages(data->pagevec, result); 744 - nfs_writedata_release(data); 745 break; 746 } 747 bytes -= pgbase; ··· 756 data->inode = inode; 757 data->cred = msg.rpc_cred; 758 data->args.fh = NFS_FH(inode); 759 - data->args.context = get_nfs_open_context(ctx); 760 data->args.offset = pos; 761 data->args.pgbase = pgbase; 762 data->args.pages = data->pagevec;
··· 255 256 if (put_dreq(dreq)) 257 nfs_direct_complete(dreq); 258 + nfs_readdata_free(data); 259 } 260 261 static const struct rpc_call_ops nfs_read_direct_ops = { ··· 314 data->npages, 1, 0, data->pagevec, NULL); 315 up_read(&current->mm->mmap_sem); 316 if (result < 0) { 317 + nfs_readdata_free(data); 318 break; 319 } 320 if ((unsigned)result < data->npages) { 321 bytes = result * PAGE_SIZE; 322 if (bytes <= pgbase) { 323 nfs_direct_release_pages(data->pagevec, result); 324 + nfs_readdata_free(data); 325 break; 326 } 327 bytes -= pgbase; ··· 334 data->inode = inode; 335 data->cred = msg.rpc_cred; 336 data->args.fh = NFS_FH(inode); 337 + data->args.context = ctx; 338 data->args.offset = pos; 339 data->args.pgbase = pgbase; 340 data->args.pages = data->pagevec; ··· 441 struct nfs_write_data *data = list_entry(dreq->rewrite_list.next, struct nfs_write_data, pages); 442 list_del(&data->pages); 443 nfs_direct_release_pages(data->pagevec, data->npages); 444 + nfs_writedata_free(data); 445 } 446 } 447 ··· 534 535 dprintk("NFS: %5u commit returned %d\n", data->task.tk_pid, status); 536 nfs_direct_write_complete(dreq, data->inode); 537 + nfs_commit_free(data); 538 } 539 540 static const struct rpc_call_ops nfs_commit_direct_ops = { ··· 570 data->args.fh = NFS_FH(data->inode); 571 data->args.offset = 0; 572 data->args.count = 0; 573 + data->args.context = dreq->ctx; 574 data->res.count = 0; 575 data->res.fattr = &data->fattr; 576 data->res.verf = &data->verf; ··· 734 data->npages, 0, 0, data->pagevec, NULL); 735 up_read(&current->mm->mmap_sem); 736 if (result < 0) { 737 + nfs_writedata_free(data); 738 break; 739 } 740 if ((unsigned)result < data->npages) { 741 bytes = result * PAGE_SIZE; 742 if (bytes <= pgbase) { 743 nfs_direct_release_pages(data->pagevec, result); 744 + nfs_writedata_free(data); 745 break; 746 } 747 bytes -= pgbase; ··· 756 data->inode = inode; 757 data->cred = msg.rpc_cred; 758 data->args.fh = NFS_FH(inode); 759 + data->args.context = ctx; 760 data->args.offset = pos; 761 data->args.pgbase = pgbase; 762 data->args.pages = data->pagevec;
+2 -4
fs/nfs/read.c
··· 60 return p; 61 } 62 63 - static void nfs_readdata_free(struct nfs_read_data *p) 64 { 65 if (p && (p->pagevec != &p->page_array[0])) 66 kfree(p->pagevec); 67 mempool_free(p, nfs_rdata_mempool); 68 } 69 70 - void nfs_readdata_release(void *data) 71 { 72 - struct nfs_read_data *rdata = data; 73 - 74 put_nfs_open_context(rdata->args.context); 75 nfs_readdata_free(rdata); 76 }
··· 60 return p; 61 } 62 63 + void nfs_readdata_free(struct nfs_read_data *p) 64 { 65 if (p && (p->pagevec != &p->page_array[0])) 66 kfree(p->pagevec); 67 mempool_free(p, nfs_rdata_mempool); 68 } 69 70 + static void nfs_readdata_release(struct nfs_read_data *rdata) 71 { 72 put_nfs_open_context(rdata->args.context); 73 nfs_readdata_free(rdata); 74 }
+2 -4
fs/nfs/write.c
··· 87 return p; 88 } 89 90 - static void nfs_writedata_free(struct nfs_write_data *p) 91 { 92 if (p && (p->pagevec != &p->page_array[0])) 93 kfree(p->pagevec); 94 mempool_free(p, nfs_wdata_mempool); 95 } 96 97 - void nfs_writedata_release(void *data) 98 { 99 - struct nfs_write_data *wdata = data; 100 - 101 put_nfs_open_context(wdata->args.context); 102 nfs_writedata_free(wdata); 103 }
··· 87 return p; 88 } 89 90 + void nfs_writedata_free(struct nfs_write_data *p) 91 { 92 if (p && (p->pagevec != &p->page_array[0])) 93 kfree(p->pagevec); 94 mempool_free(p, nfs_wdata_mempool); 95 } 96 97 + static void nfs_writedata_release(struct nfs_write_data *wdata) 98 { 99 put_nfs_open_context(wdata->args.context); 100 nfs_writedata_free(wdata); 101 }
+2 -3
include/linux/nfs_fs.h
··· 473 extern int nfs_flush_incompatible(struct file *file, struct page *page); 474 extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int); 475 extern int nfs_writeback_done(struct rpc_task *, struct nfs_write_data *); 476 - extern void nfs_writedata_release(void *); 477 478 /* 479 * Try to write back everything synchronously (but check the ··· 487 extern int nfs_commit_inode(struct inode *, int); 488 extern struct nfs_write_data *nfs_commitdata_alloc(void); 489 extern void nfs_commit_free(struct nfs_write_data *wdata); 490 - extern void nfs_commitdata_release(void *wdata); 491 #else 492 static inline int 493 nfs_commit_inode(struct inode *inode, int how) ··· 505 * Allocate nfs_write_data structures 506 */ 507 extern struct nfs_write_data *nfs_writedata_alloc(unsigned int npages); 508 509 /* 510 * linux/fs/nfs/read.c ··· 514 extern int nfs_readpages(struct file *, struct address_space *, 515 struct list_head *, unsigned); 516 extern int nfs_readpage_result(struct rpc_task *, struct nfs_read_data *); 517 - extern void nfs_readdata_release(void *data); 518 extern int nfs_readpage_async(struct nfs_open_context *, struct inode *, 519 struct page *); 520 ··· 521 * Allocate nfs_read_data structures 522 */ 523 extern struct nfs_read_data *nfs_readdata_alloc(unsigned int npages); 524 525 /* 526 * linux/fs/nfs3proc.c
··· 473 extern int nfs_flush_incompatible(struct file *file, struct page *page); 474 extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int); 475 extern int nfs_writeback_done(struct rpc_task *, struct nfs_write_data *); 476 477 /* 478 * Try to write back everything synchronously (but check the ··· 488 extern int nfs_commit_inode(struct inode *, int); 489 extern struct nfs_write_data *nfs_commitdata_alloc(void); 490 extern void nfs_commit_free(struct nfs_write_data *wdata); 491 #else 492 static inline int 493 nfs_commit_inode(struct inode *inode, int how) ··· 507 * Allocate nfs_write_data structures 508 */ 509 extern struct nfs_write_data *nfs_writedata_alloc(unsigned int npages); 510 + extern void nfs_writedata_free(struct nfs_write_data *); 511 512 /* 513 * linux/fs/nfs/read.c ··· 515 extern int nfs_readpages(struct file *, struct address_space *, 516 struct list_head *, unsigned); 517 extern int nfs_readpage_result(struct rpc_task *, struct nfs_read_data *); 518 extern int nfs_readpage_async(struct nfs_open_context *, struct inode *, 519 struct page *); 520 ··· 523 * Allocate nfs_read_data structures 524 */ 525 extern struct nfs_read_data *nfs_readdata_alloc(unsigned int npages); 526 + extern void nfs_readdata_free(struct nfs_read_data *); 527 528 /* 529 * linux/fs/nfs3proc.c