diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 109 |
1 files changed, 62 insertions, 47 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 39896afc6edf..1406858bae6c 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -1683,6 +1683,14 @@ static void nfs_state_set_open_stateid(struct nfs4_state *state, | |||
1683 | write_sequnlock(&state->seqlock); | 1683 | write_sequnlock(&state->seqlock); |
1684 | } | 1684 | } |
1685 | 1685 | ||
1686 | static void nfs_state_clear_open_state_flags(struct nfs4_state *state) | ||
1687 | { | ||
1688 | clear_bit(NFS_O_RDWR_STATE, &state->flags); | ||
1689 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
1690 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); | ||
1691 | clear_bit(NFS_OPEN_STATE, &state->flags); | ||
1692 | } | ||
1693 | |||
1686 | static void nfs_state_set_delegation(struct nfs4_state *state, | 1694 | static void nfs_state_set_delegation(struct nfs4_state *state, |
1687 | const nfs4_stateid *deleg_stateid, | 1695 | const nfs4_stateid *deleg_stateid, |
1688 | fmode_t fmode) | 1696 | fmode_t fmode) |
@@ -1907,8 +1915,9 @@ _nfs4_opendata_reclaim_to_nfs4_state(struct nfs4_opendata *data) | |||
1907 | if (data->o_res.delegation_type != 0) | 1915 | if (data->o_res.delegation_type != 0) |
1908 | nfs4_opendata_check_deleg(data, state); | 1916 | nfs4_opendata_check_deleg(data, state); |
1909 | update: | 1917 | update: |
1910 | update_open_stateid(state, &data->o_res.stateid, NULL, | 1918 | if (!update_open_stateid(state, &data->o_res.stateid, |
1911 | data->o_arg.fmode); | 1919 | NULL, data->o_arg.fmode)) |
1920 | return ERR_PTR(-EAGAIN); | ||
1912 | refcount_inc(&state->count); | 1921 | refcount_inc(&state->count); |
1913 | 1922 | ||
1914 | return state; | 1923 | return state; |
@@ -1973,8 +1982,11 @@ _nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data) | |||
1973 | 1982 | ||
1974 | if (data->o_res.delegation_type != 0) | 1983 | if (data->o_res.delegation_type != 0) |
1975 | nfs4_opendata_check_deleg(data, state); | 1984 | nfs4_opendata_check_deleg(data, state); |
1976 | update_open_stateid(state, &data->o_res.stateid, NULL, | 1985 | if (!update_open_stateid(state, &data->o_res.stateid, |
1977 | data->o_arg.fmode); | 1986 | NULL, data->o_arg.fmode)) { |
1987 | nfs4_put_open_state(state); | ||
1988 | state = ERR_PTR(-EAGAIN); | ||
1989 | } | ||
1978 | out: | 1990 | out: |
1979 | nfs_release_seqid(data->o_arg.seqid); | 1991 | nfs_release_seqid(data->o_arg.seqid); |
1980 | return state; | 1992 | return state; |
@@ -2074,13 +2086,7 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state * | |||
2074 | { | 2086 | { |
2075 | int ret; | 2087 | int ret; |
2076 | 2088 | ||
2077 | /* Don't trigger recovery in nfs_test_and_clear_all_open_stateid */ | ||
2078 | clear_bit(NFS_O_RDWR_STATE, &state->flags); | ||
2079 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
2080 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); | ||
2081 | /* memory barrier prior to reading state->n_* */ | 2089 | /* memory barrier prior to reading state->n_* */ |
2082 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | ||
2083 | clear_bit(NFS_OPEN_STATE, &state->flags); | ||
2084 | smp_rmb(); | 2090 | smp_rmb(); |
2085 | ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE); | 2091 | ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE); |
2086 | if (ret != 0) | 2092 | if (ret != 0) |
@@ -2156,6 +2162,8 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta | |||
2156 | ctx = nfs4_state_find_open_context(state); | 2162 | ctx = nfs4_state_find_open_context(state); |
2157 | if (IS_ERR(ctx)) | 2163 | if (IS_ERR(ctx)) |
2158 | return -EAGAIN; | 2164 | return -EAGAIN; |
2165 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | ||
2166 | nfs_state_clear_open_state_flags(state); | ||
2159 | ret = nfs4_do_open_reclaim(ctx, state); | 2167 | ret = nfs4_do_open_reclaim(ctx, state); |
2160 | put_nfs_open_context(ctx); | 2168 | put_nfs_open_context(ctx); |
2161 | return ret; | 2169 | return ret; |
@@ -2171,18 +2179,17 @@ static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct | |||
2171 | case -ENOENT: | 2179 | case -ENOENT: |
2172 | case -EAGAIN: | 2180 | case -EAGAIN: |
2173 | case -ESTALE: | 2181 | case -ESTALE: |
2182 | case -ETIMEDOUT: | ||
2174 | break; | 2183 | break; |
2175 | case -NFS4ERR_BADSESSION: | 2184 | case -NFS4ERR_BADSESSION: |
2176 | case -NFS4ERR_BADSLOT: | 2185 | case -NFS4ERR_BADSLOT: |
2177 | case -NFS4ERR_BAD_HIGH_SLOT: | 2186 | case -NFS4ERR_BAD_HIGH_SLOT: |
2178 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | 2187 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: |
2179 | case -NFS4ERR_DEADSESSION: | 2188 | case -NFS4ERR_DEADSESSION: |
2180 | set_bit(NFS_DELEGATED_STATE, &state->flags); | ||
2181 | nfs4_schedule_session_recovery(server->nfs_client->cl_session, err); | 2189 | nfs4_schedule_session_recovery(server->nfs_client->cl_session, err); |
2182 | return -EAGAIN; | 2190 | return -EAGAIN; |
2183 | case -NFS4ERR_STALE_CLIENTID: | 2191 | case -NFS4ERR_STALE_CLIENTID: |
2184 | case -NFS4ERR_STALE_STATEID: | 2192 | case -NFS4ERR_STALE_STATEID: |
2185 | set_bit(NFS_DELEGATED_STATE, &state->flags); | ||
2186 | /* Don't recall a delegation if it was lost */ | 2193 | /* Don't recall a delegation if it was lost */ |
2187 | nfs4_schedule_lease_recovery(server->nfs_client); | 2194 | nfs4_schedule_lease_recovery(server->nfs_client); |
2188 | return -EAGAIN; | 2195 | return -EAGAIN; |
@@ -2203,7 +2210,6 @@ static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct | |||
2203 | return -EAGAIN; | 2210 | return -EAGAIN; |
2204 | case -NFS4ERR_DELAY: | 2211 | case -NFS4ERR_DELAY: |
2205 | case -NFS4ERR_GRACE: | 2212 | case -NFS4ERR_GRACE: |
2206 | set_bit(NFS_DELEGATED_STATE, &state->flags); | ||
2207 | ssleep(1); | 2213 | ssleep(1); |
2208 | return -EAGAIN; | 2214 | return -EAGAIN; |
2209 | case -ENOMEM: | 2215 | case -ENOMEM: |
@@ -2219,8 +2225,7 @@ static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct | |||
2219 | } | 2225 | } |
2220 | 2226 | ||
2221 | int nfs4_open_delegation_recall(struct nfs_open_context *ctx, | 2227 | int nfs4_open_delegation_recall(struct nfs_open_context *ctx, |
2222 | struct nfs4_state *state, const nfs4_stateid *stateid, | 2228 | struct nfs4_state *state, const nfs4_stateid *stateid) |
2223 | fmode_t type) | ||
2224 | { | 2229 | { |
2225 | struct nfs_server *server = NFS_SERVER(state->inode); | 2230 | struct nfs_server *server = NFS_SERVER(state->inode); |
2226 | struct nfs4_opendata *opendata; | 2231 | struct nfs4_opendata *opendata; |
@@ -2231,20 +2236,23 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, | |||
2231 | if (IS_ERR(opendata)) | 2236 | if (IS_ERR(opendata)) |
2232 | return PTR_ERR(opendata); | 2237 | return PTR_ERR(opendata); |
2233 | nfs4_stateid_copy(&opendata->o_arg.u.delegation, stateid); | 2238 | nfs4_stateid_copy(&opendata->o_arg.u.delegation, stateid); |
2234 | nfs_state_clear_delegation(state); | 2239 | if (!test_bit(NFS_O_RDWR_STATE, &state->flags)) { |
2235 | switch (type & (FMODE_READ|FMODE_WRITE)) { | ||
2236 | case FMODE_READ|FMODE_WRITE: | ||
2237 | case FMODE_WRITE: | ||
2238 | err = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE); | 2240 | err = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE); |
2239 | if (err) | 2241 | if (err) |
2240 | break; | 2242 | goto out; |
2243 | } | ||
2244 | if (!test_bit(NFS_O_WRONLY_STATE, &state->flags)) { | ||
2241 | err = nfs4_open_recover_helper(opendata, FMODE_WRITE); | 2245 | err = nfs4_open_recover_helper(opendata, FMODE_WRITE); |
2242 | if (err) | 2246 | if (err) |
2243 | break; | 2247 | goto out; |
2244 | /* Fall through */ | 2248 | } |
2245 | case FMODE_READ: | 2249 | if (!test_bit(NFS_O_RDONLY_STATE, &state->flags)) { |
2246 | err = nfs4_open_recover_helper(opendata, FMODE_READ); | 2250 | err = nfs4_open_recover_helper(opendata, FMODE_READ); |
2251 | if (err) | ||
2252 | goto out; | ||
2247 | } | 2253 | } |
2254 | nfs_state_clear_delegation(state); | ||
2255 | out: | ||
2248 | nfs4_opendata_put(opendata); | 2256 | nfs4_opendata_put(opendata); |
2249 | return nfs4_handle_delegation_recall_error(server, state, stateid, NULL, err); | 2257 | return nfs4_handle_delegation_recall_error(server, state, stateid, NULL, err); |
2250 | } | 2258 | } |
@@ -2492,6 +2500,7 @@ static int nfs4_run_open_task(struct nfs4_opendata *data, | |||
2492 | if (!ctx) { | 2500 | if (!ctx) { |
2493 | nfs4_init_sequence(&o_arg->seq_args, &o_res->seq_res, 1, 1); | 2501 | nfs4_init_sequence(&o_arg->seq_args, &o_res->seq_res, 1, 1); |
2494 | data->is_recover = true; | 2502 | data->is_recover = true; |
2503 | task_setup_data.flags |= RPC_TASK_TIMEOUT; | ||
2495 | } else { | 2504 | } else { |
2496 | nfs4_init_sequence(&o_arg->seq_args, &o_res->seq_res, 1, 0); | 2505 | nfs4_init_sequence(&o_arg->seq_args, &o_res->seq_res, 1, 0); |
2497 | pnfs_lgopen_prepare(data, ctx); | 2506 | pnfs_lgopen_prepare(data, ctx); |
@@ -2698,6 +2707,7 @@ static int nfs40_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st | |||
2698 | { | 2707 | { |
2699 | /* NFSv4.0 doesn't allow for delegation recovery on open expire */ | 2708 | /* NFSv4.0 doesn't allow for delegation recovery on open expire */ |
2700 | nfs40_clear_delegation_stateid(state); | 2709 | nfs40_clear_delegation_stateid(state); |
2710 | nfs_state_clear_open_state_flags(state); | ||
2701 | return nfs4_open_expired(sp, state); | 2711 | return nfs4_open_expired(sp, state); |
2702 | } | 2712 | } |
2703 | 2713 | ||
@@ -2740,13 +2750,13 @@ out_free: | |||
2740 | return -NFS4ERR_EXPIRED; | 2750 | return -NFS4ERR_EXPIRED; |
2741 | } | 2751 | } |
2742 | 2752 | ||
2743 | static void nfs41_check_delegation_stateid(struct nfs4_state *state) | 2753 | static int nfs41_check_delegation_stateid(struct nfs4_state *state) |
2744 | { | 2754 | { |
2745 | struct nfs_server *server = NFS_SERVER(state->inode); | 2755 | struct nfs_server *server = NFS_SERVER(state->inode); |
2746 | nfs4_stateid stateid; | 2756 | nfs4_stateid stateid; |
2747 | struct nfs_delegation *delegation; | 2757 | struct nfs_delegation *delegation; |
2748 | const struct cred *cred = NULL; | 2758 | const struct cred *cred = NULL; |
2749 | int status; | 2759 | int status, ret = NFS_OK; |
2750 | 2760 | ||
2751 | /* Get the delegation credential for use by test/free_stateid */ | 2761 | /* Get the delegation credential for use by test/free_stateid */ |
2752 | rcu_read_lock(); | 2762 | rcu_read_lock(); |
@@ -2754,20 +2764,15 @@ static void nfs41_check_delegation_stateid(struct nfs4_state *state) | |||
2754 | if (delegation == NULL) { | 2764 | if (delegation == NULL) { |
2755 | rcu_read_unlock(); | 2765 | rcu_read_unlock(); |
2756 | nfs_state_clear_delegation(state); | 2766 | nfs_state_clear_delegation(state); |
2757 | return; | 2767 | return NFS_OK; |
2758 | } | 2768 | } |
2759 | 2769 | ||
2760 | nfs4_stateid_copy(&stateid, &delegation->stateid); | 2770 | nfs4_stateid_copy(&stateid, &delegation->stateid); |
2761 | if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) { | ||
2762 | rcu_read_unlock(); | ||
2763 | nfs_state_clear_delegation(state); | ||
2764 | return; | ||
2765 | } | ||
2766 | 2771 | ||
2767 | if (!test_and_clear_bit(NFS_DELEGATION_TEST_EXPIRED, | 2772 | if (!test_and_clear_bit(NFS_DELEGATION_TEST_EXPIRED, |
2768 | &delegation->flags)) { | 2773 | &delegation->flags)) { |
2769 | rcu_read_unlock(); | 2774 | rcu_read_unlock(); |
2770 | return; | 2775 | return NFS_OK; |
2771 | } | 2776 | } |
2772 | 2777 | ||
2773 | if (delegation->cred) | 2778 | if (delegation->cred) |
@@ -2777,9 +2782,24 @@ static void nfs41_check_delegation_stateid(struct nfs4_state *state) | |||
2777 | trace_nfs4_test_delegation_stateid(state, NULL, status); | 2782 | trace_nfs4_test_delegation_stateid(state, NULL, status); |
2778 | if (status == -NFS4ERR_EXPIRED || status == -NFS4ERR_BAD_STATEID) | 2783 | if (status == -NFS4ERR_EXPIRED || status == -NFS4ERR_BAD_STATEID) |
2779 | nfs_finish_clear_delegation_stateid(state, &stateid); | 2784 | nfs_finish_clear_delegation_stateid(state, &stateid); |
2785 | else | ||
2786 | ret = status; | ||
2780 | 2787 | ||
2781 | if (delegation->cred) | 2788 | put_cred(cred); |
2782 | put_cred(cred); | 2789 | return ret; |
2790 | } | ||
2791 | |||
2792 | static void nfs41_delegation_recover_stateid(struct nfs4_state *state) | ||
2793 | { | ||
2794 | nfs4_stateid tmp; | ||
2795 | |||
2796 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) && | ||
2797 | nfs4_copy_delegation_stateid(state->inode, state->state, | ||
2798 | &tmp, NULL) && | ||
2799 | nfs4_stateid_match_other(&state->stateid, &tmp)) | ||
2800 | nfs_state_set_delegation(state, &tmp, state->state); | ||
2801 | else | ||
2802 | nfs_state_clear_delegation(state); | ||
2783 | } | 2803 | } |
2784 | 2804 | ||
2785 | /** | 2805 | /** |
@@ -2849,21 +2869,12 @@ static int nfs41_check_open_stateid(struct nfs4_state *state) | |||
2849 | const struct cred *cred = state->owner->so_cred; | 2869 | const struct cred *cred = state->owner->so_cred; |
2850 | int status; | 2870 | int status; |
2851 | 2871 | ||
2852 | if (test_bit(NFS_OPEN_STATE, &state->flags) == 0) { | 2872 | if (test_bit(NFS_OPEN_STATE, &state->flags) == 0) |
2853 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) { | ||
2854 | if (nfs4_have_delegation(state->inode, state->state)) | ||
2855 | return NFS_OK; | ||
2856 | return -NFS4ERR_OPENMODE; | ||
2857 | } | ||
2858 | return -NFS4ERR_BAD_STATEID; | 2873 | return -NFS4ERR_BAD_STATEID; |
2859 | } | ||
2860 | status = nfs41_test_and_free_expired_stateid(server, stateid, cred); | 2874 | status = nfs41_test_and_free_expired_stateid(server, stateid, cred); |
2861 | trace_nfs4_test_open_stateid(state, NULL, status); | 2875 | trace_nfs4_test_open_stateid(state, NULL, status); |
2862 | if (status == -NFS4ERR_EXPIRED || status == -NFS4ERR_BAD_STATEID) { | 2876 | if (status == -NFS4ERR_EXPIRED || status == -NFS4ERR_BAD_STATEID) { |
2863 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); | 2877 | nfs_state_clear_open_state_flags(state); |
2864 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
2865 | clear_bit(NFS_O_RDWR_STATE, &state->flags); | ||
2866 | clear_bit(NFS_OPEN_STATE, &state->flags); | ||
2867 | stateid->type = NFS4_INVALID_STATEID_TYPE; | 2878 | stateid->type = NFS4_INVALID_STATEID_TYPE; |
2868 | return status; | 2879 | return status; |
2869 | } | 2880 | } |
@@ -2876,7 +2887,11 @@ static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st | |||
2876 | { | 2887 | { |
2877 | int status; | 2888 | int status; |
2878 | 2889 | ||
2879 | nfs41_check_delegation_stateid(state); | 2890 | status = nfs41_check_delegation_stateid(state); |
2891 | if (status != NFS_OK) | ||
2892 | return status; | ||
2893 | nfs41_delegation_recover_stateid(state); | ||
2894 | |||
2880 | status = nfs41_check_expired_locks(state); | 2895 | status = nfs41_check_expired_locks(state); |
2881 | if (status != NFS_OK) | 2896 | if (status != NFS_OK) |
2882 | return status; | 2897 | return status; |
@@ -3201,7 +3216,7 @@ static int _nfs4_do_setattr(struct inode *inode, | |||
3201 | 3216 | ||
3202 | if (nfs4_copy_delegation_stateid(inode, FMODE_WRITE, &arg->stateid, &delegation_cred)) { | 3217 | if (nfs4_copy_delegation_stateid(inode, FMODE_WRITE, &arg->stateid, &delegation_cred)) { |
3203 | /* Use that stateid */ | 3218 | /* Use that stateid */ |
3204 | } else if (ctx != NULL) { | 3219 | } else if (ctx != NULL && ctx->state) { |
3205 | struct nfs_lock_context *l_ctx; | 3220 | struct nfs_lock_context *l_ctx; |
3206 | if (!nfs4_valid_open_stateid(ctx->state)) | 3221 | if (!nfs4_valid_open_stateid(ctx->state)) |
3207 | return -EBADF; | 3222 | return -EBADF; |