diff options
Diffstat (limited to 'fs/nfs/inode.c')
| -rw-r--r-- | fs/nfs/inode.c | 70 | 
1 files changed, 28 insertions, 42 deletions
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index b65aee481d13..5b1eee4952b7 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -857,15 +857,14 @@ static void nfs_init_lock_context(struct nfs_lock_context *l_ctx)  static struct nfs_lock_context *__nfs_find_lock_context(struct nfs_open_context *ctx)  { -	struct nfs_lock_context *head = &ctx->lock_context; -	struct nfs_lock_context *pos = head; +	struct nfs_lock_context *pos; -	do { +	list_for_each_entry_rcu(pos, &ctx->lock_context.list, list) {  		if (pos->lockowner != current->files)  			continue; -		refcount_inc(&pos->count); -		return pos; -	} while ((pos = list_entry(pos->list.next, typeof(*pos), list)) != head); +		if (refcount_inc_not_zero(&pos->count)) +			return pos; +	}  	return NULL;  } @@ -874,10 +873,10 @@ struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx)  	struct nfs_lock_context *res, *new = NULL;  	struct inode *inode = d_inode(ctx->dentry); -	spin_lock(&inode->i_lock); +	rcu_read_lock();  	res = __nfs_find_lock_context(ctx); +	rcu_read_unlock();  	if (res == NULL) { -		spin_unlock(&inode->i_lock);  		new = kmalloc(sizeof(*new), GFP_KERNEL);  		if (new == NULL)  			return ERR_PTR(-ENOMEM); @@ -885,14 +884,14 @@ struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx)  		spin_lock(&inode->i_lock);  		res = __nfs_find_lock_context(ctx);  		if (res == NULL) { -			list_add_tail(&new->list, &ctx->lock_context.list); +			list_add_tail_rcu(&new->list, &ctx->lock_context.list);  			new->open_context = ctx;  			res = new;  			new = NULL;  		} +		spin_unlock(&inode->i_lock); +		kfree(new);  	} -	spin_unlock(&inode->i_lock); -	kfree(new);  	return res;  }  EXPORT_SYMBOL_GPL(nfs_get_lock_context); @@ -904,9 +903,9 @@ void nfs_put_lock_context(struct nfs_lock_context *l_ctx)  	if (!refcount_dec_and_lock(&l_ctx->count, &inode->i_lock))  		return; -	list_del(&l_ctx->list); +	list_del_rcu(&l_ctx->list);  	spin_unlock(&inode->i_lock); -	kfree(l_ctx); +	kfree_rcu(l_ctx, rcu_head);  }  EXPORT_SYMBOL_GPL(nfs_put_lock_context); @@ -978,9 +977,9 @@ EXPORT_SYMBOL_GPL(alloc_nfs_open_context);  struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx)  { -	if (ctx != NULL) -		refcount_inc(&ctx->lock_context.count); -	return ctx; +	if (ctx != NULL && refcount_inc_not_zero(&ctx->lock_context.count)) +		return ctx; +	return NULL;  }  EXPORT_SYMBOL_GPL(get_nfs_open_context); @@ -989,13 +988,13 @@ static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync)  	struct inode *inode = d_inode(ctx->dentry);  	struct super_block *sb = ctx->dentry->d_sb; +	if (!refcount_dec_and_test(&ctx->lock_context.count)) +		return;  	if (!list_empty(&ctx->list)) { -		if (!refcount_dec_and_lock(&ctx->lock_context.count, &inode->i_lock)) -			return; -		list_del(&ctx->list); +		spin_lock(&inode->i_lock); +		list_del_rcu(&ctx->list);  		spin_unlock(&inode->i_lock); -	} else if (!refcount_dec_and_test(&ctx->lock_context.count)) -		return; +	}  	if (inode != NULL)  		NFS_PROTO(inode)->close_context(ctx, is_sync);  	if (ctx->cred != NULL) @@ -1003,7 +1002,7 @@ static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync)  	dput(ctx->dentry);  	nfs_sb_deactive(sb);  	kfree(ctx->mdsthreshold); -	kfree(ctx); +	kfree_rcu(ctx, rcu_head);  }  void put_nfs_open_context(struct nfs_open_context *ctx) @@ -1027,10 +1026,7 @@ void nfs_inode_attach_open_context(struct nfs_open_context *ctx)  	struct nfs_inode *nfsi = NFS_I(inode);  	spin_lock(&inode->i_lock); -	if (ctx->mode & FMODE_WRITE) -		list_add(&ctx->list, &nfsi->open_files); -	else -		list_add_tail(&ctx->list, &nfsi->open_files); +	list_add_tail_rcu(&ctx->list, &nfsi->open_files);  	spin_unlock(&inode->i_lock);  }  EXPORT_SYMBOL_GPL(nfs_inode_attach_open_context); @@ -1051,16 +1047,17 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_c  	struct nfs_inode *nfsi = NFS_I(inode);  	struct nfs_open_context *pos, *ctx = NULL; -	spin_lock(&inode->i_lock); -	list_for_each_entry(pos, &nfsi->open_files, list) { +	rcu_read_lock(); +	list_for_each_entry_rcu(pos, &nfsi->open_files, list) {  		if (cred != NULL && pos->cred != cred)  			continue;  		if ((pos->mode & (FMODE_READ|FMODE_WRITE)) != mode)  			continue;  		ctx = get_nfs_open_context(pos); -		break; +		if (ctx) +			break;  	} -	spin_unlock(&inode->i_lock); +	rcu_read_unlock();  	return ctx;  } @@ -1078,9 +1075,6 @@ void nfs_file_clear_open_context(struct file *filp)  		if (ctx->error < 0)  			invalidate_inode_pages2(inode->i_mapping);  		filp->private_data = NULL; -		spin_lock(&inode->i_lock); -		list_move_tail(&ctx->list, &NFS_I(inode)->open_files); -		spin_unlock(&inode->i_lock);  		put_nfs_open_context_sync(ctx);  	}  } @@ -1329,19 +1323,11 @@ static bool nfs_file_has_writers(struct nfs_inode *nfsi)  {  	struct inode *inode = &nfsi->vfs_inode; -	assert_spin_locked(&inode->i_lock); -  	if (!S_ISREG(inode->i_mode))  		return false;  	if (list_empty(&nfsi->open_files))  		return false; -	/* Note: This relies on nfsi->open_files being ordered with writers -	 *       being placed at the head of the list. -	 *       See nfs_inode_attach_open_context() -	 */ -	return (list_first_entry(&nfsi->open_files, -			struct nfs_open_context, -			list)->mode & FMODE_WRITE) == FMODE_WRITE; +	return inode_is_open_for_write(inode);  }  static bool nfs_file_has_buffered_writers(struct nfs_inode *nfsi)  | 
