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