Loading fs/nfs/nfs4proc.c +50 −15 Original line number Original line Diff line number Diff line Loading @@ -83,8 +83,10 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, struct nfs_fattr *fattr, struct iattr *sattr, struct nfs_fattr *fattr, struct iattr *sattr, struct nfs4_state *state); struct nfs4_state *state); #ifdef CONFIG_NFS_V4_1 #ifdef CONFIG_NFS_V4_1 static int nfs41_test_stateid(struct nfs_server *, nfs4_stateid *); static int nfs41_test_stateid(struct nfs_server *, nfs4_stateid *, static int nfs41_free_stateid(struct nfs_server *, nfs4_stateid *); struct rpc_cred *); static int nfs41_free_stateid(struct nfs_server *, nfs4_stateid *, struct rpc_cred *); #endif #endif /* Prevent leaks of NFSv4 errors into userland */ /* Prevent leaks of NFSv4 errors into userland */ static int nfs4_map_errors(int err) static int nfs4_map_errors(int err) Loading Loading @@ -1855,18 +1857,30 @@ static void nfs41_clear_delegation_stateid(struct nfs4_state *state) { { struct nfs_server *server = NFS_SERVER(state->inode); struct nfs_server *server = NFS_SERVER(state->inode); nfs4_stateid *stateid = &state->stateid; nfs4_stateid *stateid = &state->stateid; int status; struct nfs_delegation *delegation; struct rpc_cred *cred = NULL; int status = -NFS4ERR_BAD_STATEID; /* If a state reset has been done, test_stateid is unneeded */ /* If a state reset has been done, test_stateid is unneeded */ if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) return; return; status = nfs41_test_stateid(server, stateid); /* Get the delegation credential for use by test/free_stateid */ rcu_read_lock(); delegation = rcu_dereference(NFS_I(state->inode)->delegation); if (delegation != NULL && nfs4_stateid_match(&delegation->stateid, stateid)) { cred = get_rpccred(delegation->cred); rcu_read_unlock(); status = nfs41_test_stateid(server, stateid, cred); } else rcu_read_unlock(); if (status != NFS_OK) { if (status != NFS_OK) { /* Free the stateid unless the server explicitly /* Free the stateid unless the server explicitly * informs us the stateid is unrecognized. */ * informs us the stateid is unrecognized. */ if (status != -NFS4ERR_BAD_STATEID) if (status != -NFS4ERR_BAD_STATEID) nfs41_free_stateid(server, stateid); nfs41_free_stateid(server, stateid, cred); nfs_remove_bad_delegation(state->inode); nfs_remove_bad_delegation(state->inode); write_seqlock(&state->seqlock); write_seqlock(&state->seqlock); Loading @@ -1874,6 +1888,9 @@ static void nfs41_clear_delegation_stateid(struct nfs4_state *state) write_sequnlock(&state->seqlock); write_sequnlock(&state->seqlock); clear_bit(NFS_DELEGATED_STATE, &state->flags); clear_bit(NFS_DELEGATED_STATE, &state->flags); } } if (cred != NULL) put_rpccred(cred); } } /** /** Loading @@ -1888,6 +1905,7 @@ static int nfs41_check_open_stateid(struct nfs4_state *state) { { struct nfs_server *server = NFS_SERVER(state->inode); struct nfs_server *server = NFS_SERVER(state->inode); nfs4_stateid *stateid = &state->open_stateid; nfs4_stateid *stateid = &state->open_stateid; struct rpc_cred *cred = state->owner->so_cred; int status; int status; /* If a state reset has been done, test_stateid is unneeded */ /* If a state reset has been done, test_stateid is unneeded */ Loading @@ -1896,12 +1914,12 @@ static int nfs41_check_open_stateid(struct nfs4_state *state) (test_bit(NFS_O_RDWR_STATE, &state->flags) == 0)) (test_bit(NFS_O_RDWR_STATE, &state->flags) == 0)) return -NFS4ERR_BAD_STATEID; return -NFS4ERR_BAD_STATEID; status = nfs41_test_stateid(server, stateid); status = nfs41_test_stateid(server, stateid, cred); if (status != NFS_OK) { if (status != NFS_OK) { /* Free the stateid unless the server explicitly /* Free the stateid unless the server explicitly * informs us the stateid is unrecognized. */ * informs us the stateid is unrecognized. */ if (status != -NFS4ERR_BAD_STATEID) if (status != -NFS4ERR_BAD_STATEID) nfs41_free_stateid(server, stateid); nfs41_free_stateid(server, stateid, cred); clear_bit(NFS_O_RDONLY_STATE, &state->flags); clear_bit(NFS_O_RDONLY_STATE, &state->flags); clear_bit(NFS_O_WRONLY_STATE, &state->flags); clear_bit(NFS_O_WRONLY_STATE, &state->flags); Loading Loading @@ -5056,13 +5074,18 @@ static int nfs41_check_expired_locks(struct nfs4_state *state) list_for_each_entry(lsp, &state->lock_states, ls_locks) { list_for_each_entry(lsp, &state->lock_states, ls_locks) { if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) { if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) { status = nfs41_test_stateid(server, &lsp->ls_stateid); struct rpc_cred *cred = lsp->ls_state->owner->so_cred; status = nfs41_test_stateid(server, &lsp->ls_stateid, cred); if (status != NFS_OK) { if (status != NFS_OK) { /* Free the stateid unless the server /* Free the stateid unless the server * informs us the stateid is unrecognized. */ * informs us the stateid is unrecognized. */ if (status != -NFS4ERR_BAD_STATEID) if (status != -NFS4ERR_BAD_STATEID) nfs41_free_stateid(server, nfs41_free_stateid(server, &lsp->ls_stateid); &lsp->ls_stateid, cred); clear_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags); clear_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags); ret = status; ret = status; } } Loading Loading @@ -6737,7 +6760,9 @@ out: return err; return err; } } static int _nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid) static int _nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid, struct rpc_cred *cred) { { int status; int status; struct nfs41_test_stateid_args args = { struct nfs41_test_stateid_args args = { Loading @@ -6748,6 +6773,7 @@ static int _nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid) .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_TEST_STATEID], .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_TEST_STATEID], .rpc_argp = &args, .rpc_argp = &args, .rpc_resp = &res, .rpc_resp = &res, .rpc_cred = cred, }; }; dprintk("NFS call test_stateid %p\n", stateid); dprintk("NFS call test_stateid %p\n", stateid); Loading @@ -6768,17 +6794,20 @@ static int _nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid) * * * @server: server / transport on which to perform the operation * @server: server / transport on which to perform the operation * @stateid: state ID to test * @stateid: state ID to test * @cred: credential * * * Returns NFS_OK if the server recognizes that "stateid" is valid. * Returns NFS_OK if the server recognizes that "stateid" is valid. * Otherwise a negative NFS4ERR value is returned if the operation * Otherwise a negative NFS4ERR value is returned if the operation * failed or the state ID is not currently valid. * failed or the state ID is not currently valid. */ */ static int nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid) static int nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid, struct rpc_cred *cred) { { struct nfs4_exception exception = { }; struct nfs4_exception exception = { }; int err; int err; do { do { err = _nfs41_test_stateid(server, stateid); err = _nfs41_test_stateid(server, stateid, cred); if (err != -NFS4ERR_DELAY) if (err != -NFS4ERR_DELAY) break; break; nfs4_handle_exception(server, err, &exception); nfs4_handle_exception(server, err, &exception); Loading Loading @@ -6827,10 +6856,12 @@ const struct rpc_call_ops nfs41_free_stateid_ops = { static struct rpc_task *_nfs41_free_stateid(struct nfs_server *server, static struct rpc_task *_nfs41_free_stateid(struct nfs_server *server, nfs4_stateid *stateid, nfs4_stateid *stateid, struct rpc_cred *cred, bool privileged) bool privileged) { { struct rpc_message msg = { struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FREE_STATEID], .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FREE_STATEID], .rpc_cred = cred, }; }; struct rpc_task_setup task_setup = { struct rpc_task_setup task_setup = { .rpc_client = server->client, .rpc_client = server->client, Loading Loading @@ -6863,16 +6894,19 @@ static struct rpc_task *_nfs41_free_stateid(struct nfs_server *server, * * * @server: server / transport on which to perform the operation * @server: server / transport on which to perform the operation * @stateid: state ID to release * @stateid: state ID to release * @cred: credential * * * Returns NFS_OK if the server freed "stateid". Otherwise a * Returns NFS_OK if the server freed "stateid". Otherwise a * negative NFS4ERR value is returned. * negative NFS4ERR value is returned. */ */ static int nfs41_free_stateid(struct nfs_server *server, nfs4_stateid *stateid) static int nfs41_free_stateid(struct nfs_server *server, nfs4_stateid *stateid, struct rpc_cred *cred) { { struct rpc_task *task; struct rpc_task *task; int ret; int ret; task = _nfs41_free_stateid(server, stateid, true); task = _nfs41_free_stateid(server, stateid, cred, true); if (IS_ERR(task)) if (IS_ERR(task)) return PTR_ERR(task); return PTR_ERR(task); ret = rpc_wait_for_completion_task(task); ret = rpc_wait_for_completion_task(task); Loading @@ -6885,8 +6919,9 @@ static int nfs41_free_stateid(struct nfs_server *server, nfs4_stateid *stateid) static int nfs41_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp) static int nfs41_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp) { { struct rpc_task *task; struct rpc_task *task; struct rpc_cred *cred = lsp->ls_state->owner->so_cred; task = _nfs41_free_stateid(server, &lsp->ls_stateid, false); task = _nfs41_free_stateid(server, &lsp->ls_stateid, cred, false); nfs4_free_lock_state(server, lsp); nfs4_free_lock_state(server, lsp); if (IS_ERR(task)) if (IS_ERR(task)) return PTR_ERR(task); return PTR_ERR(task); Loading Loading
fs/nfs/nfs4proc.c +50 −15 Original line number Original line Diff line number Diff line Loading @@ -83,8 +83,10 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, struct nfs_fattr *fattr, struct iattr *sattr, struct nfs_fattr *fattr, struct iattr *sattr, struct nfs4_state *state); struct nfs4_state *state); #ifdef CONFIG_NFS_V4_1 #ifdef CONFIG_NFS_V4_1 static int nfs41_test_stateid(struct nfs_server *, nfs4_stateid *); static int nfs41_test_stateid(struct nfs_server *, nfs4_stateid *, static int nfs41_free_stateid(struct nfs_server *, nfs4_stateid *); struct rpc_cred *); static int nfs41_free_stateid(struct nfs_server *, nfs4_stateid *, struct rpc_cred *); #endif #endif /* Prevent leaks of NFSv4 errors into userland */ /* Prevent leaks of NFSv4 errors into userland */ static int nfs4_map_errors(int err) static int nfs4_map_errors(int err) Loading Loading @@ -1855,18 +1857,30 @@ static void nfs41_clear_delegation_stateid(struct nfs4_state *state) { { struct nfs_server *server = NFS_SERVER(state->inode); struct nfs_server *server = NFS_SERVER(state->inode); nfs4_stateid *stateid = &state->stateid; nfs4_stateid *stateid = &state->stateid; int status; struct nfs_delegation *delegation; struct rpc_cred *cred = NULL; int status = -NFS4ERR_BAD_STATEID; /* If a state reset has been done, test_stateid is unneeded */ /* If a state reset has been done, test_stateid is unneeded */ if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) return; return; status = nfs41_test_stateid(server, stateid); /* Get the delegation credential for use by test/free_stateid */ rcu_read_lock(); delegation = rcu_dereference(NFS_I(state->inode)->delegation); if (delegation != NULL && nfs4_stateid_match(&delegation->stateid, stateid)) { cred = get_rpccred(delegation->cred); rcu_read_unlock(); status = nfs41_test_stateid(server, stateid, cred); } else rcu_read_unlock(); if (status != NFS_OK) { if (status != NFS_OK) { /* Free the stateid unless the server explicitly /* Free the stateid unless the server explicitly * informs us the stateid is unrecognized. */ * informs us the stateid is unrecognized. */ if (status != -NFS4ERR_BAD_STATEID) if (status != -NFS4ERR_BAD_STATEID) nfs41_free_stateid(server, stateid); nfs41_free_stateid(server, stateid, cred); nfs_remove_bad_delegation(state->inode); nfs_remove_bad_delegation(state->inode); write_seqlock(&state->seqlock); write_seqlock(&state->seqlock); Loading @@ -1874,6 +1888,9 @@ static void nfs41_clear_delegation_stateid(struct nfs4_state *state) write_sequnlock(&state->seqlock); write_sequnlock(&state->seqlock); clear_bit(NFS_DELEGATED_STATE, &state->flags); clear_bit(NFS_DELEGATED_STATE, &state->flags); } } if (cred != NULL) put_rpccred(cred); } } /** /** Loading @@ -1888,6 +1905,7 @@ static int nfs41_check_open_stateid(struct nfs4_state *state) { { struct nfs_server *server = NFS_SERVER(state->inode); struct nfs_server *server = NFS_SERVER(state->inode); nfs4_stateid *stateid = &state->open_stateid; nfs4_stateid *stateid = &state->open_stateid; struct rpc_cred *cred = state->owner->so_cred; int status; int status; /* If a state reset has been done, test_stateid is unneeded */ /* If a state reset has been done, test_stateid is unneeded */ Loading @@ -1896,12 +1914,12 @@ static int nfs41_check_open_stateid(struct nfs4_state *state) (test_bit(NFS_O_RDWR_STATE, &state->flags) == 0)) (test_bit(NFS_O_RDWR_STATE, &state->flags) == 0)) return -NFS4ERR_BAD_STATEID; return -NFS4ERR_BAD_STATEID; status = nfs41_test_stateid(server, stateid); status = nfs41_test_stateid(server, stateid, cred); if (status != NFS_OK) { if (status != NFS_OK) { /* Free the stateid unless the server explicitly /* Free the stateid unless the server explicitly * informs us the stateid is unrecognized. */ * informs us the stateid is unrecognized. */ if (status != -NFS4ERR_BAD_STATEID) if (status != -NFS4ERR_BAD_STATEID) nfs41_free_stateid(server, stateid); nfs41_free_stateid(server, stateid, cred); clear_bit(NFS_O_RDONLY_STATE, &state->flags); clear_bit(NFS_O_RDONLY_STATE, &state->flags); clear_bit(NFS_O_WRONLY_STATE, &state->flags); clear_bit(NFS_O_WRONLY_STATE, &state->flags); Loading Loading @@ -5056,13 +5074,18 @@ static int nfs41_check_expired_locks(struct nfs4_state *state) list_for_each_entry(lsp, &state->lock_states, ls_locks) { list_for_each_entry(lsp, &state->lock_states, ls_locks) { if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) { if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) { status = nfs41_test_stateid(server, &lsp->ls_stateid); struct rpc_cred *cred = lsp->ls_state->owner->so_cred; status = nfs41_test_stateid(server, &lsp->ls_stateid, cred); if (status != NFS_OK) { if (status != NFS_OK) { /* Free the stateid unless the server /* Free the stateid unless the server * informs us the stateid is unrecognized. */ * informs us the stateid is unrecognized. */ if (status != -NFS4ERR_BAD_STATEID) if (status != -NFS4ERR_BAD_STATEID) nfs41_free_stateid(server, nfs41_free_stateid(server, &lsp->ls_stateid); &lsp->ls_stateid, cred); clear_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags); clear_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags); ret = status; ret = status; } } Loading Loading @@ -6737,7 +6760,9 @@ out: return err; return err; } } static int _nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid) static int _nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid, struct rpc_cred *cred) { { int status; int status; struct nfs41_test_stateid_args args = { struct nfs41_test_stateid_args args = { Loading @@ -6748,6 +6773,7 @@ static int _nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid) .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_TEST_STATEID], .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_TEST_STATEID], .rpc_argp = &args, .rpc_argp = &args, .rpc_resp = &res, .rpc_resp = &res, .rpc_cred = cred, }; }; dprintk("NFS call test_stateid %p\n", stateid); dprintk("NFS call test_stateid %p\n", stateid); Loading @@ -6768,17 +6794,20 @@ static int _nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid) * * * @server: server / transport on which to perform the operation * @server: server / transport on which to perform the operation * @stateid: state ID to test * @stateid: state ID to test * @cred: credential * * * Returns NFS_OK if the server recognizes that "stateid" is valid. * Returns NFS_OK if the server recognizes that "stateid" is valid. * Otherwise a negative NFS4ERR value is returned if the operation * Otherwise a negative NFS4ERR value is returned if the operation * failed or the state ID is not currently valid. * failed or the state ID is not currently valid. */ */ static int nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid) static int nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid, struct rpc_cred *cred) { { struct nfs4_exception exception = { }; struct nfs4_exception exception = { }; int err; int err; do { do { err = _nfs41_test_stateid(server, stateid); err = _nfs41_test_stateid(server, stateid, cred); if (err != -NFS4ERR_DELAY) if (err != -NFS4ERR_DELAY) break; break; nfs4_handle_exception(server, err, &exception); nfs4_handle_exception(server, err, &exception); Loading Loading @@ -6827,10 +6856,12 @@ const struct rpc_call_ops nfs41_free_stateid_ops = { static struct rpc_task *_nfs41_free_stateid(struct nfs_server *server, static struct rpc_task *_nfs41_free_stateid(struct nfs_server *server, nfs4_stateid *stateid, nfs4_stateid *stateid, struct rpc_cred *cred, bool privileged) bool privileged) { { struct rpc_message msg = { struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FREE_STATEID], .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FREE_STATEID], .rpc_cred = cred, }; }; struct rpc_task_setup task_setup = { struct rpc_task_setup task_setup = { .rpc_client = server->client, .rpc_client = server->client, Loading Loading @@ -6863,16 +6894,19 @@ static struct rpc_task *_nfs41_free_stateid(struct nfs_server *server, * * * @server: server / transport on which to perform the operation * @server: server / transport on which to perform the operation * @stateid: state ID to release * @stateid: state ID to release * @cred: credential * * * Returns NFS_OK if the server freed "stateid". Otherwise a * Returns NFS_OK if the server freed "stateid". Otherwise a * negative NFS4ERR value is returned. * negative NFS4ERR value is returned. */ */ static int nfs41_free_stateid(struct nfs_server *server, nfs4_stateid *stateid) static int nfs41_free_stateid(struct nfs_server *server, nfs4_stateid *stateid, struct rpc_cred *cred) { { struct rpc_task *task; struct rpc_task *task; int ret; int ret; task = _nfs41_free_stateid(server, stateid, true); task = _nfs41_free_stateid(server, stateid, cred, true); if (IS_ERR(task)) if (IS_ERR(task)) return PTR_ERR(task); return PTR_ERR(task); ret = rpc_wait_for_completion_task(task); ret = rpc_wait_for_completion_task(task); Loading @@ -6885,8 +6919,9 @@ static int nfs41_free_stateid(struct nfs_server *server, nfs4_stateid *stateid) static int nfs41_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp) static int nfs41_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp) { { struct rpc_task *task; struct rpc_task *task; struct rpc_cred *cred = lsp->ls_state->owner->so_cred; task = _nfs41_free_stateid(server, &lsp->ls_stateid, false); task = _nfs41_free_stateid(server, &lsp->ls_stateid, cred, false); nfs4_free_lock_state(server, lsp); nfs4_free_lock_state(server, lsp); if (IS_ERR(task)) if (IS_ERR(task)) return PTR_ERR(task); return PTR_ERR(task); Loading