Commit 7952f4999f338ea23845e3419ad0963db147c910

Authored by Trond Myklebust
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

... ... @@ -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
... ... @@ -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;
... ... @@ -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