Commit 7952f4999f338ea23845e3419ad0963db147c910
Committed by
Greg Kroah-Hartman
1 parent
bcc9c506f2
NFSv4: Ensure we reference the inode for return-on-close in delegreturn
commit ea7c38fef0b774a5dc16fb0ca5935f0ae8568176 upstream. If we have to do a return-on-close in the delegreturn code, then we must ensure that the inode and super block remain referenced. Cc: Peng Tao <tao.peng@primarydata.com> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com> Reviewed-by: Peng Tao <tao.peng@primarydata.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Showing 3 changed files with 36 additions and 9 deletions Side-by-side Diff
fs/nfs/internal.h
... | ... | @@ -377,7 +377,7 @@ |
377 | 377 | |
378 | 378 | extern int __init register_nfs_fs(void); |
379 | 379 | extern void __exit unregister_nfs_fs(void); |
380 | -extern void nfs_sb_active(struct super_block *sb); | |
380 | +extern bool nfs_sb_active(struct super_block *sb); | |
381 | 381 | extern void nfs_sb_deactive(struct super_block *sb); |
382 | 382 | |
383 | 383 | /* namespace.c */ |
... | ... | @@ -494,6 +494,26 @@ |
494 | 494 | extern int nfs41_walk_client_list(struct nfs_client *clp, |
495 | 495 | struct nfs_client **result, |
496 | 496 | struct rpc_cred *cred); |
497 | + | |
498 | +static inline struct inode *nfs_igrab_and_active(struct inode *inode) | |
499 | +{ | |
500 | + inode = igrab(inode); | |
501 | + if (inode != NULL && !nfs_sb_active(inode->i_sb)) { | |
502 | + iput(inode); | |
503 | + inode = NULL; | |
504 | + } | |
505 | + return inode; | |
506 | +} | |
507 | + | |
508 | +static inline void nfs_iput_and_deactive(struct inode *inode) | |
509 | +{ | |
510 | + if (inode != NULL) { | |
511 | + struct super_block *sb = inode->i_sb; | |
512 | + | |
513 | + iput(inode); | |
514 | + nfs_sb_deactive(sb); | |
515 | + } | |
516 | +} | |
497 | 517 | |
498 | 518 | /* |
499 | 519 | * Determine the device name as a string |
fs/nfs/nfs4proc.c
... | ... | @@ -5130,9 +5130,13 @@ |
5130 | 5130 | static void nfs4_delegreturn_release(void *calldata) |
5131 | 5131 | { |
5132 | 5132 | struct nfs4_delegreturndata *data = calldata; |
5133 | + struct inode *inode = data->inode; | |
5133 | 5134 | |
5134 | - if (data->roc) | |
5135 | - pnfs_roc_release(data->inode); | |
5135 | + if (inode) { | |
5136 | + if (data->roc) | |
5137 | + pnfs_roc_release(inode); | |
5138 | + nfs_iput_and_deactive(inode); | |
5139 | + } | |
5136 | 5140 | kfree(calldata); |
5137 | 5141 | } |
5138 | 5142 | |
... | ... | @@ -5189,9 +5193,9 @@ |
5189 | 5193 | nfs_fattr_init(data->res.fattr); |
5190 | 5194 | data->timestamp = jiffies; |
5191 | 5195 | data->rpc_status = 0; |
5192 | - data->inode = inode; | |
5193 | - data->roc = list_empty(&NFS_I(inode)->open_files) ? | |
5194 | - pnfs_roc(inode) : false; | |
5196 | + data->inode = nfs_igrab_and_active(inode); | |
5197 | + if (data->inode) | |
5198 | + data->roc = nfs4_roc(inode); | |
5195 | 5199 | |
5196 | 5200 | task_setup_data.callback_data = data; |
5197 | 5201 | msg.rpc_argp = &data->args; |
fs/nfs/super.c
... | ... | @@ -405,12 +405,15 @@ |
405 | 405 | unregister_filesystem(&nfs_fs_type); |
406 | 406 | } |
407 | 407 | |
408 | -void nfs_sb_active(struct super_block *sb) | |
408 | +bool nfs_sb_active(struct super_block *sb) | |
409 | 409 | { |
410 | 410 | struct nfs_server *server = NFS_SB(sb); |
411 | 411 | |
412 | - if (atomic_inc_return(&server->active) == 1) | |
413 | - atomic_inc(&sb->s_active); | |
412 | + if (!atomic_inc_not_zero(&sb->s_active)) | |
413 | + return false; | |
414 | + if (atomic_inc_return(&server->active) != 1) | |
415 | + atomic_dec(&sb->s_active); | |
416 | + return true; | |
414 | 417 | } |
415 | 418 | EXPORT_SYMBOL_GPL(nfs_sb_active); |
416 | 419 |