diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-03-19 16:17:18 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-03-20 13:08:25 -0400 |
commit | 5ae67c4fee869c9b3c87b727a9ea511b6326b834 (patch) | |
tree | 68fe22b71462c6e13eff3a6d637b79371c77441e /fs/nfs | |
parent | c4f1b62a4b50a01e8d820717906b674807ef9ca3 (diff) |
NFSv4: It is not safe to dereference lsp->ls_state in release_lockowner
It is quite possible for the release_lockowner RPC call to race with the
close RPC call, in which case, we cannot dereference lsp->ls_state in
order to find the nfs_server.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/nfs4_fs.h | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 4 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 8 |
3 files changed, 7 insertions, 7 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index b47bdb9c1612..97ecc863dd76 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -340,7 +340,7 @@ extern void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid); | |||
340 | extern void nfs_release_seqid(struct nfs_seqid *seqid); | 340 | extern void nfs_release_seqid(struct nfs_seqid *seqid); |
341 | extern void nfs_free_seqid(struct nfs_seqid *seqid); | 341 | extern void nfs_free_seqid(struct nfs_seqid *seqid); |
342 | 342 | ||
343 | extern void nfs4_free_lock_state(struct nfs4_lock_state *lsp); | 343 | extern void nfs4_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp); |
344 | 344 | ||
345 | extern const nfs4_stateid zero_stateid; | 345 | extern const nfs4_stateid zero_stateid; |
346 | 346 | ||
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 5e0961acfef4..d41d97fb4cb9 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -4760,13 +4760,14 @@ out: | |||
4760 | 4760 | ||
4761 | struct nfs_release_lockowner_data { | 4761 | struct nfs_release_lockowner_data { |
4762 | struct nfs4_lock_state *lsp; | 4762 | struct nfs4_lock_state *lsp; |
4763 | struct nfs_server *server; | ||
4763 | struct nfs_release_lockowner_args args; | 4764 | struct nfs_release_lockowner_args args; |
4764 | }; | 4765 | }; |
4765 | 4766 | ||
4766 | static void nfs4_release_lockowner_release(void *calldata) | 4767 | static void nfs4_release_lockowner_release(void *calldata) |
4767 | { | 4768 | { |
4768 | struct nfs_release_lockowner_data *data = calldata; | 4769 | struct nfs_release_lockowner_data *data = calldata; |
4769 | nfs4_free_lock_state(data->lsp); | 4770 | nfs4_free_lock_state(data->server, data->lsp); |
4770 | kfree(calldata); | 4771 | kfree(calldata); |
4771 | } | 4772 | } |
4772 | 4773 | ||
@@ -4788,6 +4789,7 @@ int nfs4_release_lockowner(struct nfs4_lock_state *lsp) | |||
4788 | if (!data) | 4789 | if (!data) |
4789 | return -ENOMEM; | 4790 | return -ENOMEM; |
4790 | data->lsp = lsp; | 4791 | data->lsp = lsp; |
4792 | data->server = server; | ||
4791 | data->args.lock_owner.clientid = server->nfs_client->cl_clientid; | 4793 | data->args.lock_owner.clientid = server->nfs_client->cl_clientid; |
4792 | data->args.lock_owner.id = lsp->ls_seqid.owner_id; | 4794 | data->args.lock_owner.id = lsp->ls_seqid.owner_id; |
4793 | data->args.lock_owner.s_dev = server->s_dev; | 4795 | data->args.lock_owner.s_dev = server->s_dev; |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 12b068f2ec91..0f43414eb25a 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -791,10 +791,8 @@ out_free: | |||
791 | return NULL; | 791 | return NULL; |
792 | } | 792 | } |
793 | 793 | ||
794 | void nfs4_free_lock_state(struct nfs4_lock_state *lsp) | 794 | void nfs4_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp) |
795 | { | 795 | { |
796 | struct nfs_server *server = lsp->ls_state->owner->so_server; | ||
797 | |||
798 | ida_simple_remove(&server->lockowner_id, lsp->ls_seqid.owner_id); | 796 | ida_simple_remove(&server->lockowner_id, lsp->ls_seqid.owner_id); |
799 | nfs4_destroy_seqid_counter(&lsp->ls_seqid); | 797 | nfs4_destroy_seqid_counter(&lsp->ls_seqid); |
800 | kfree(lsp); | 798 | kfree(lsp); |
@@ -828,7 +826,7 @@ static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_ | |||
828 | } | 826 | } |
829 | spin_unlock(&state->state_lock); | 827 | spin_unlock(&state->state_lock); |
830 | if (new != NULL) | 828 | if (new != NULL) |
831 | nfs4_free_lock_state(new); | 829 | nfs4_free_lock_state(state->owner->so_server, new); |
832 | return lsp; | 830 | return lsp; |
833 | } | 831 | } |
834 | 832 | ||
@@ -853,7 +851,7 @@ void nfs4_put_lock_state(struct nfs4_lock_state *lsp) | |||
853 | if (nfs4_release_lockowner(lsp) == 0) | 851 | if (nfs4_release_lockowner(lsp) == 0) |
854 | return; | 852 | return; |
855 | } | 853 | } |
856 | nfs4_free_lock_state(lsp); | 854 | nfs4_free_lock_state(lsp->ls_state->owner->so_server, lsp); |
857 | } | 855 | } |
858 | 856 | ||
859 | static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src) | 857 | static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src) |