diff options
-rw-r--r-- | fs/nfs/nfs4state.c | 130 |
1 files changed, 81 insertions, 49 deletions
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 401ef8b28f97..99182b3229e7 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -811,7 +811,7 @@ void nfs4_schedule_state_recovery(struct nfs_client *clp) | |||
811 | nfs4_recover_state(clp); | 811 | nfs4_recover_state(clp); |
812 | } | 812 | } |
813 | 813 | ||
814 | static int nfs4_reclaim_locks(struct nfs4_state_recovery_ops *ops, struct nfs4_state *state) | 814 | static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops) |
815 | { | 815 | { |
816 | struct inode *inode = state->inode; | 816 | struct inode *inode = state->inode; |
817 | struct file_lock *fl; | 817 | struct file_lock *fl; |
@@ -844,7 +844,7 @@ out_err: | |||
844 | return status; | 844 | return status; |
845 | } | 845 | } |
846 | 846 | ||
847 | static int nfs4_reclaim_open_state(struct nfs4_state_recovery_ops *ops, struct nfs4_state_owner *sp) | 847 | static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs4_state_recovery_ops *ops) |
848 | { | 848 | { |
849 | struct nfs4_state *state; | 849 | struct nfs4_state *state; |
850 | struct nfs4_lock_state *lock; | 850 | struct nfs4_lock_state *lock; |
@@ -863,15 +863,15 @@ static int nfs4_reclaim_open_state(struct nfs4_state_recovery_ops *ops, struct n | |||
863 | continue; | 863 | continue; |
864 | status = ops->recover_open(sp, state); | 864 | status = ops->recover_open(sp, state); |
865 | if (status >= 0) { | 865 | if (status >= 0) { |
866 | status = nfs4_reclaim_locks(ops, state); | 866 | status = nfs4_reclaim_locks(state, ops); |
867 | if (status < 0) | 867 | if (status >= 0) { |
868 | goto out_err; | 868 | list_for_each_entry(lock, &state->lock_states, ls_locks) { |
869 | list_for_each_entry(lock, &state->lock_states, ls_locks) { | 869 | if (!(lock->ls_flags & NFS_LOCK_INITIALIZED)) |
870 | if (!(lock->ls_flags & NFS_LOCK_INITIALIZED)) | 870 | printk("%s: Lock reclaim failed!\n", |
871 | printk("%s: Lock reclaim failed!\n", | ||
872 | __func__); | 871 | __func__); |
872 | } | ||
873 | continue; | ||
873 | } | 874 | } |
874 | continue; | ||
875 | } | 875 | } |
876 | switch (status) { | 876 | switch (status) { |
877 | default: | 877 | default: |
@@ -928,45 +928,45 @@ static void nfs4_state_mark_reclaim(struct nfs_client *clp) | |||
928 | } | 928 | } |
929 | } | 929 | } |
930 | 930 | ||
931 | static int reclaimer(void *ptr) | 931 | static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recovery_ops *ops) |
932 | { | 932 | { |
933 | struct nfs_client *clp = ptr; | ||
934 | struct nfs4_state_owner *sp; | ||
935 | struct rb_node *pos; | 933 | struct rb_node *pos; |
936 | struct nfs4_state_recovery_ops *ops; | ||
937 | struct rpc_cred *cred; | ||
938 | int status = 0; | 934 | int status = 0; |
939 | 935 | ||
940 | allow_signal(SIGKILL); | 936 | /* Note: list is protected by exclusive lock on cl->cl_sem */ |
937 | for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) { | ||
938 | struct nfs4_state_owner *sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); | ||
939 | status = nfs4_reclaim_open_state(sp, ops); | ||
940 | if (status < 0) | ||
941 | break; | ||
942 | } | ||
943 | return status; | ||
944 | } | ||
945 | |||
946 | static int nfs4_check_lease(struct nfs_client *clp) | ||
947 | { | ||
948 | struct rpc_cred *cred; | ||
949 | int status = -NFS4ERR_EXPIRED; | ||
941 | 950 | ||
942 | /* Ensure exclusive access to NFSv4 state */ | ||
943 | down_write(&clp->cl_sem); | ||
944 | /* Are there any NFS mounts out there? */ | ||
945 | if (list_empty(&clp->cl_superblocks)) | ||
946 | goto out; | ||
947 | restart_loop: | ||
948 | ops = &nfs4_network_partition_recovery_ops; | ||
949 | /* Are there any open files on this volume? */ | 951 | /* Are there any open files on this volume? */ |
950 | cred = nfs4_get_renew_cred(clp); | 952 | cred = nfs4_get_renew_cred(clp); |
951 | if (cred != NULL) { | 953 | if (cred != NULL) { |
952 | /* Yes there are: try to renew the old lease */ | 954 | /* Yes there are: try to renew the old lease */ |
953 | status = nfs4_proc_renew(clp, cred); | 955 | status = nfs4_proc_renew(clp, cred); |
954 | put_rpccred(cred); | 956 | put_rpccred(cred); |
955 | switch (status) { | 957 | return status; |
956 | case 0: | ||
957 | case -NFS4ERR_CB_PATH_DOWN: | ||
958 | goto out; | ||
959 | case -NFS4ERR_STALE_CLIENTID: | ||
960 | case -NFS4ERR_LEASE_MOVED: | ||
961 | ops = &nfs4_reboot_recovery_ops; | ||
962 | } | ||
963 | } else { | ||
964 | /* "reboot" to ensure we clear all state on the server */ | ||
965 | clp->cl_boot_time = CURRENT_TIME; | ||
966 | } | 958 | } |
967 | /* We're going to have to re-establish a clientid */ | 959 | |
968 | nfs4_state_mark_reclaim(clp); | 960 | /* "reboot" to ensure we clear all state on the server */ |
969 | status = -ENOENT; | 961 | clp->cl_boot_time = CURRENT_TIME; |
962 | return status; | ||
963 | } | ||
964 | |||
965 | static int nfs4_reclaim_lease(struct nfs_client *clp) | ||
966 | { | ||
967 | struct rpc_cred *cred; | ||
968 | int status = -ENOENT; | ||
969 | |||
970 | cred = nfs4_get_setclientid_cred(clp); | 970 | cred = nfs4_get_setclientid_cred(clp); |
971 | if (cred != NULL) { | 971 | if (cred != NULL) { |
972 | status = nfs4_init_client(clp, cred); | 972 | status = nfs4_init_client(clp, cred); |
@@ -974,29 +974,61 @@ restart_loop: | |||
974 | /* Handle case where the user hasn't set up machine creds */ | 974 | /* Handle case where the user hasn't set up machine creds */ |
975 | if (status == -EACCES && cred == clp->cl_machine_cred) { | 975 | if (status == -EACCES && cred == clp->cl_machine_cred) { |
976 | nfs4_clear_machine_cred(clp); | 976 | nfs4_clear_machine_cred(clp); |
977 | goto restart_loop; | 977 | status = -EAGAIN; |
978 | } | 978 | } |
979 | } | 979 | } |
980 | if (status) | 980 | return status; |
981 | goto out_error; | 981 | } |
982 | /* Mark all delegations for reclaim */ | 982 | |
983 | nfs_delegation_mark_reclaim(clp); | 983 | static int reclaimer(void *ptr) |
984 | /* Note: list is protected by exclusive lock on cl->cl_sem */ | 984 | { |
985 | for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) { | 985 | struct nfs_client *clp = ptr; |
986 | sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); | 986 | const struct nfs4_state_recovery_ops *ops; |
987 | status = nfs4_reclaim_open_state(ops, sp); | 987 | int status = 0; |
988 | |||
989 | allow_signal(SIGKILL); | ||
990 | |||
991 | /* Ensure exclusive access to NFSv4 state */ | ||
992 | down_write(&clp->cl_sem); | ||
993 | while (!list_empty(&clp->cl_superblocks)) { | ||
994 | ops = &nfs4_network_partition_recovery_ops; | ||
995 | status = nfs4_check_lease(clp); | ||
996 | switch (status) { | ||
997 | case 0: | ||
998 | case -NFS4ERR_CB_PATH_DOWN: | ||
999 | goto out; | ||
1000 | case -NFS4ERR_STALE_CLIENTID: | ||
1001 | case -NFS4ERR_LEASE_MOVED: | ||
1002 | ops = &nfs4_reboot_recovery_ops; | ||
1003 | } | ||
1004 | |||
1005 | /* We're going to have to re-establish a clientid */ | ||
1006 | nfs4_state_mark_reclaim(clp); | ||
1007 | |||
1008 | status = nfs4_reclaim_lease(clp); | ||
1009 | if (status) { | ||
1010 | if (status == -EAGAIN) | ||
1011 | continue; | ||
1012 | goto out_error; | ||
1013 | } | ||
1014 | |||
1015 | /* Mark all delegations for reclaim */ | ||
1016 | nfs_delegation_mark_reclaim(clp); | ||
1017 | /* Note: list is protected by exclusive lock on cl->cl_sem */ | ||
1018 | status = nfs4_do_reclaim(clp, ops); | ||
988 | if (status < 0) { | 1019 | if (status < 0) { |
989 | if (status == -NFS4ERR_NO_GRACE) { | 1020 | if (status == -NFS4ERR_NO_GRACE) { |
990 | ops = &nfs4_network_partition_recovery_ops; | 1021 | ops = &nfs4_network_partition_recovery_ops; |
991 | status = nfs4_reclaim_open_state(ops, sp); | 1022 | status = nfs4_do_reclaim(clp, ops); |
992 | } | 1023 | } |
993 | if (status == -NFS4ERR_STALE_CLIENTID) | 1024 | if (status == -NFS4ERR_STALE_CLIENTID) |
994 | goto restart_loop; | 1025 | continue; |
995 | if (status == -NFS4ERR_EXPIRED) | 1026 | if (status == -NFS4ERR_EXPIRED) |
996 | goto restart_loop; | 1027 | continue; |
997 | } | 1028 | } |
1029 | nfs_delegation_reap_unclaimed(clp); | ||
1030 | break; | ||
998 | } | 1031 | } |
999 | nfs_delegation_reap_unclaimed(clp); | ||
1000 | out: | 1032 | out: |
1001 | up_write(&clp->cl_sem); | 1033 | up_write(&clp->cl_sem); |
1002 | if (status == -NFS4ERR_CB_PATH_DOWN) | 1034 | if (status == -NFS4ERR_CB_PATH_DOWN) |