Initial SP4_MACH_CRED implementation
Subsystems (2)
cover Initial SP4_MACH_CRED implementation
This is version 2 of this patchset including some cleanup, refactoring and fixes a few build issues with different configs.
I also added a few patches:
- WRITE and/or COMMIT support - tested on a hacked nfsd
- map NFS4ERR_WRONG_CRED (an common SP4 error) to EPERM
I meant to include a patch that only uses the machine cred (for 'allow' ops) when the user cred has expired, but after talking with Andy, I decided to wait for his cred expiration patchset to be merged as we'd be touching the same places and possibly duplicating effort.
Weston Andros Adamson (7):
nfs4.1: Minimal SP4_MACH_CRED implementation nfs4.1: Add state protection handler nfs4.1: Add SP4_MACH_CRED cleanup support nfs4.1: Add SP4_MACH_CRED secinfo support nfs4.1: Add SP4_MACH_CRED stateid support nfs4.1: Add SP4_MACH_CRED write and commit support
nfs4: Map NFS4ERR_WRONG_CRED to EPERM
fs/nfs/nfs4_fs.h | 67 ++++++++++++++++ fs/nfs/nfs4proc.c | 191 ++++++++++++++++++++++++++++++++++++++++++++-- fs/nfs/nfs4xdr.c | 72 ++++++++++++++--- fs/nfs/write.c | 6 ++ include/linux/nfs_fs_sb.h | 9 +++ include/linux/nfs_xdr.h | 19 +++++ 6 files changed, 346 insertions(+), 18 deletions(-)
Signature · 1 line
1.7.12.4 (Apple Git-37)
PATCH 1/7 nfs4.1: Minimal SP4_MACH_CRED implementation
This is a minimal client side implementation of SP4_MACH_CRED. It will attempt to negotiate SP4_MACH_CRED iff the EXCHANGE_ID is using krb5i or krb5p auth. SP4_MACH_CRED will be used if the server supports the minimal operations:
BIND_CONN_TO_SESSION
EXCHANGE_ID
CREATE_SESSION
DESTROY_SESSION
DESTROY_CLIENTID
This patch only includes the EXCHANGE_ID negotiation code because the client will already use the machine cred for these operations.
If the server doesn't support SP4_MACH_CRED or doesn't support the minimal operations, the exchange id will be resent with SP4_NONE.
--- fs/nfs/nfs4proc.c | 133 +++++++++++++++++++++++++++++++++++++++++++--- fs/nfs/nfs4xdr.c | 72 +++++++++++++++++++++---- include/linux/nfs_fs_sb.h | 4 ++ include/linux/nfs_xdr.h | 19 +++++++ 4 files changed, 211 insertions(+), 17 deletions(-)
fs/nfs/nfs4proc.c +126 -7
@@ -5918,16 +5918,87 @@ out: }/* -* nfs4_proc_exchange_id() +* Minimum set of SP4_MACH_CRED operations from RFC 5661 +*/ +static const struct nfs41_state_protection nfs4_sp4_mach_cred_request = { + .how =SP4_MACH_CRED , + .enforce.u.words = { + [1 ] =1 << (OP_BIND_CONN_TO_SESSION -32 ) | +1 << (OP_EXCHANGE_ID -32 ) | +1 << (OP_CREATE_SESSION -32 ) | +1 << (OP_DESTROY_SESSION -32 ) | +1 << (OP_DESTROY_CLIENTID -32 ) + } +}; + +/* +* Select the state protection mode for client `clp' given the server results +* from exchange_id in `sp'. * -* Returns zero, a negative errno, or a negative NFS4ERR status code. +* Returns 0 on success, negative errno otherwise. +*/ +static int nfs4_sp4_select_mode (struct nfs_client *clp, +struct nfs41_state_protection *sp) +{ +static const u32 supported_enforce[NFS4_OP_MAP_NUM_WORDS ] = { + [1 ] =1 << (OP_BIND_CONN_TO_SESSION -32 ) | +1 << (OP_EXCHANGE_ID -32 ) | +1 << (OP_CREATE_SESSION -32 ) | +1 << (OP_DESTROY_SESSION -32 ) | +1 << (OP_DESTROY_CLIENTID -32 ) + }; +unsigned int i; + +if (sp->how ==SP4_MACH_CRED ) { +/* Print state protect result */ +dfprintk (MOUNT ,"Server SP4_MACH_CRED support:\n" ); +for (i =0 ; i <=LAST_NFS4_OP ; i++) { +if (test_bit (i, sp->enforce.u.longs)) +dfprintk (MOUNT ," enforce op %d\n" , i); +if (test_bit (i, sp->allow.u.longs)) +dfprintk (MOUNT ," allow op %d\n" , i); + } + +/* make sure nothing is on enforce list that isn't supported */ +for (i =0 ; i <NFS4_OP_MAP_NUM_WORDS ; i++) { +if (sp->enforce.u.words[i] & ~supported_enforce[i]) { +dfprintk (MOUNT ,"sp4_mach_cred: disabled\n" ); +return -EINVAL ; + } + } + +/* +* Minimal mode - state operations are allowed to use machine +* credential. Note this already happens by default, so the +* client doesn't have to do anything more than the negotiation. +* +* NOTE: we don't care if EXCHANGE_ID is in the list - +* we're already using the machine cred for exchange_id +* and will never use a different cred. +*/ +if (test_bit (OP_BIND_CONN_TO_SESSION , sp->enforce.u.longs) && +test_bit (OP_CREATE_SESSION , sp->enforce.u.longs) && +test_bit (OP_DESTROY_SESSION , sp->enforce.u.longs) && +test_bit (OP_DESTROY_CLIENTID , sp->enforce.u.longs)) { +dfprintk (MOUNT ,"sp4_mach_cred:\n" ); +dfprintk (MOUNT ," minimal mode enabled\n" ); +set_bit (NFS_SP4_MACH_CRED_MINIMAL , &clp->cl_sp4_flags); + }else { +dfprintk (MOUNT ,"sp4_mach_cred: disabled\n" ); +return -EINVAL ; + } + } + +return 0 ; +} + +/* +* _nfs4_proc_exchange_id() * -* Since the clientid has expired, all compounds using sessions -* associated with the stale clientid will be returning -* NFS4ERR_BADSESSION in the sequence operation, and will therefore -* be in some phase of session reset. +* Wrapper for EXCHANGE_ID operation. */ -int nfs4_proc_exchange_id (struct nfs_client *clp,struct rpc_cred *cred) +static int _nfs4_proc_exchange_id (struct nfs_client *clp,struct rpc_cred *cred, +u32 sp4_how) {nfs4_verifier verifier;struct nfs41_exchange_id_args args = {
@@ -5974,10 +6045,29 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) goto out_server_scope; } +switch (sp4_how) { +case SP4_NONE : + args.state_protect.how =SP4_NONE ; +break ; + +case SP4_MACH_CRED : + args.state_protect = nfs4_sp4_mach_cred_request; +break ; + +default : +/* unsupported! */ +WARN_ON_ONCE (1 ); + status = -EINVAL ; + goto out_server_scope; + } + status =rpc_call_sync (clp->cl_rpcclient, &msg,RPC_TASK_TIMEOUT );if (status ==0 ) status =nfs4_check_cl_exchange_flags (res.flags); +if (status ==0 ) + status =nfs4_sp4_select_mode (clp, &res.state_protect); +if (status ==0 ) { clp->cl_clientid = res.clientid; clp->cl_exchange_flags = (res.flags & ~EXCHGID4_FLAG_CONFIRMED_R );
@@ -6024,6 +6114,35 @@ out:return status; } +/* +* nfs4_proc_exchange_id() +* +* Returns zero, a negative errno, or a negative NFS4ERR status code. +* +* Since the clientid has expired, all compounds using sessions +* associated with the stale clientid will be returning +* NFS4ERR_BADSESSION in the sequence operation, and will therefore +* be in some phase of session reset. +* +* Will attempt to negotiate SP4_MACH_CRED if krb5i / krb5p auth is used. +*/ +int nfs4_proc_exchange_id (struct nfs_client *clp,struct rpc_cred *cred) +{ +rpc_authflavor_t authflavor = clp->cl_rpcclient->cl_auth->au_flavor; +int status; + +/* try SP4_MACH_CRED if krb5i/p */ +if (authflavor ==RPC_AUTH_GSS_KRB5I || + authflavor ==RPC_AUTH_GSS_KRB5P ) { + status =_nfs4_proc_exchange_id (clp, cred,SP4_MACH_CRED ); +if (!status) +return 0 ; + } + +/* try SP4_NONE */ +return _nfs4_proc_exchange_id (clp, cred,SP4_NONE ); +} +static int _nfs4_proc_destroy_clientid (struct nfs_client *clp,struct rpc_cred *cred) {
fs/nfs/nfs4xdr.c +62 -10
121 lines not on this page · raw message
include/linux/nfs_fs_sb.h +4 -0
@@ -87,6 +87,10 @@ struct nfs_client {struct nfs41_server_owner *cl_serverowner;struct nfs41_server_scope *cl_serverscope;struct nfs41_impl_id *cl_implid; +/* nfs 4.1+ state protection modes: */ +unsigned long cl_sp4_flags; +#define NFS_SP4_MACH_CRED_MINIMAL 1/* Minimal sp4_mach_cred - state ops +* must use machine cred */ #endif /* CONFIG_NFS_V4 */ #ifdef CONFIG_NFS_FSCACHE
include/linux/nfs_xdr.h +19 -0
@@ -1107,6 +1107,23 @@ struct pnfs_ds_commit_info {struct pnfs_commit_bucket *buckets; }; +#define NFS4_OP_MAP_NUM_LONGS \ + DIV_ROUND_UP(LAST_NFS4_OP, 8 * sizeof(unsigned long)) +#define NFS4_OP_MAP_NUM_WORDS \ + (NFS4_OP_MAP_NUM_LONGS * sizeof(unsigned long) / sizeof(u32)) +struct nfs4_op_map { +union { +unsigned long longs[NFS4_OP_MAP_NUM_LONGS ]; +u32 words[NFS4_OP_MAP_NUM_WORDS ]; + } u; +}; + +struct nfs41_state_protection { +u32 how; +struct nfs4_op_map enforce; +struct nfs4_op_map allow; +}; +#define NFS4_EXCHANGE_ID_LEN (48)struct nfs41_exchange_id_args {struct nfs_client *client;
@@ -1114,6 +1131,7 @@ struct nfs41_exchange_id_args {unsigned int id_len;char id[NFS4_EXCHANGE_ID_LEN ];u32 flags; +struct nfs41_state_protection state_protect; };struct nfs41_server_owner {
@@ -1146,6 +1164,7 @@ struct nfs41_exchange_id_res {struct nfs41_server_owner *server_owner;struct nfs41_server_scope *server_scope;struct nfs41_impl_id *impl_id; +struct nfs41_state_protection state_protect; };struct nfs41_create_session_args {
Signature · 1 line
1.7.12.4 (Apple Git-37)
PATCH 2/7 nfs4.1: Add state protection handler
In reply to Weston Andros AdamsonAdd nfs4_state_protect - the function responsible for switching to the machine credential and the correct rpc client when SP4_MACH_CRED is in use.
--- fs/nfs/nfs4_fs.h | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+)
fs/nfs/nfs4_fs.h +35 -0
@@ -272,6 +272,35 @@ is_ds_client(struct nfs_client *clp) {return clp->cl_exchange_flags &EXCHGID4_FLAG_USE_PNFS_DS ; } + +/* +* Function responsible for determining if an rpc_message should use the +* machine cred under SP4_MACH_CRED and if so switching the credential and +* authflavor (using the nfs_client's rpc_clnt which will be krb5i/p). +* Should be called before rpc_call_sync/rpc_call_async. +*/ +static inline void +nfs4_state_protect (struct nfs_client *clp,unsigned long sp4_mode, +struct rpc_clnt **clntp,struct rpc_message *msg) +{ +struct rpc_cred *newcred =NULL ; +rpc_authflavor_t flavor; + +if (test_bit (sp4_mode, &clp->cl_sp4_flags)) { +spin_lock (&clp->cl_lock); +if (clp->cl_machine_cred !=NULL ) + newcred =get_rpccred (clp->cl_machine_cred); +spin_unlock (&clp->cl_lock); +if (msg->rpc_cred) +put_rpccred (msg->rpc_cred); + msg->rpc_cred = newcred; + + flavor = clp->cl_rpcclient->cl_auth->au_flavor; +WARN_ON (flavor !=RPC_AUTH_GSS_KRB5I && + flavor !=RPC_AUTH_GSS_KRB5P ); + *clntp = clp->cl_rpcclient; + } +}#else /* CONFIG_NFS_v4_1 */ static inline struct nfs4_session *nfs4_get_session (const struct nfs_server *server) {
@@ -297,6 +326,12 @@ is_ds_client(struct nfs_client *clp) {return false; } + +static inline void +nfs4_state_protect (struct nfs_client *clp,unsigned long sp4_flags, +struct rpc_clnt **clntp,struct rpc_message *msg) +{ +}#endif /* CONFIG_NFS_V4_1 */ extern const struct nfs4_minor_version_ops *nfs_v4_minor_ops[];
Signature · 1 line
1.7.12.4 (Apple Git-37)
PATCH 3/7 nfs4.1: Add SP4_MACH_CRED cleanup support
In reply to Weston Andros AdamsonCLOSE and LOCKU can use the machine credential.
--- fs/nfs/nfs4proc.c | 19 ++++++++++++++++++- include/linux/nfs_fs_sb.h | 1 + 2 files changed, 19 insertions(+), 1 deletion(-)
fs/nfs/nfs4proc.c +18 -1
@@ -2511,6 +2511,9 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait) };int status = -ENOMEM ; +nfs4_state_protect (server->nfs_client,NFS_SP4_MACH_CRED_CLEANUP , + &task_setup_data.rpc_client, &msg); + calldata =kzalloc (sizeof (*calldata), gfp_mask);if (calldata ==NULL ) goto out;
@@ -5091,6 +5094,9 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl, .flags = RPC_TASK_ASYNC, }; +nfs4_state_protect (NFS_SERVER (lsp->ls_state->inode)->nfs_client, +NFS_SP4_MACH_CRED_CLEANUP , &task_setup_data.rpc_client, &msg); +/* Ensure this is an unlock - when canceling a lock, the * canceled lock is passed in, and it won't be an unlock. */
@@ -5918,7 +5924,8 @@ out: }/* -* Minimum set of SP4_MACH_CRED operations from RFC 5661 +* Minimum set of SP4_MACH_CRED operations from RFC 5661 in the enforce map +* and operations we'd like to see to enable certain features in the allow map */ static const struct nfs41_state_protection nfs4_sp4_mach_cred_request = { .how =SP4_MACH_CRED ,
@@ -5928,6 +5935,10 @@ static const struct nfs41_state_protection nfs4_sp4_mach_cred_request = {1 << (OP_CREATE_SESSION -32 ) |1 << (OP_DESTROY_SESSION -32 ) |1 << (OP_DESTROY_CLIENTID -32 ) + }, + .allow.u.words = { + [0 ] =1 << (OP_CLOSE ) | + 1 << (OP_LOCKU) } };
@@ -5987,6 +5998,12 @@ static int nfs4_sp4_select_mode(struct nfs_client *clp,dfprintk (MOUNT ,"sp4_mach_cred: disabled\n" );return -EINVAL ; } + +if (test_bit (OP_CLOSE , sp->allow.u.longs) && +test_bit (OP_LOCKU , sp->allow.u.longs)) { +dfprintk (MOUNT ," cleanup mode enabled\n" ); +set_bit (NFS_SP4_MACH_CRED_CLEANUP , &clp->cl_sp4_flags); + } }return 0 ;
include/linux/nfs_fs_sb.h +1 -0
@@ -91,6 +91,7 @@ struct nfs_client {unsigned long cl_sp4_flags;#define NFS_SP4_MACH_CRED_MINIMAL 1/* Minimal sp4_mach_cred - state ops * must use machine cred */ +#define NFS_SP4_MACH_CRED_CLEANUP 2/* CLOSE and LOCKU */ #endif /* CONFIG_NFS_V4 */ #ifdef CONFIG_NFS_FSCACHE
Signature · 1 line
1.7.12.4 (Apple Git-37)
PATCH 4/7 nfs4.1: Add SP4_MACH_CRED secinfo support
In reply to Weston Andros AdamsonSECINFO and SECINFO_NONAME can use the machine credential.
--- fs/nfs/nfs4proc.c | 15 ++++++++++++++- include/linux/nfs_fs_sb.h | 1 + 2 files changed, 15 insertions(+), 1 deletion(-)
fs/nfs/nfs4proc.c +14 -1
@@ -5820,7 +5820,12 @@ static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, structstruct rpc_clnt *clnt =NFS_SERVER (dir)->nfs_client->cl_rpcclient;dprintk ("NFS call secinfo %s\n" , name->name); + +nfs4_state_protect (NFS_SERVER (dir)->nfs_client, +NFS_SP4_MACH_CRED_SECINFO , &clnt, &msg); + status =nfs4_call_sync (clnt,NFS_SERVER (dir), &msg, &args.seq_args, &res.seq_res,0 ); +dprintk ("NFS reply secinfo: %d\n" , status);return status; }
@@ -5938,7 +5943,9 @@ static const struct nfs41_state_protection nfs4_sp4_mach_cred_request = { }, .allow.u.words = { [0 ] =1 << (OP_CLOSE ) | -1 << (OP_LOCKU ) + 1 << (OP_LOCKU), + [1 ] =1 << (OP_SECINFO -32 ) | +1 << (OP_SECINFO_NO_NAME -32 ) } };
@@ -6004,6 +6011,12 @@ static int nfs4_sp4_select_mode(struct nfs_client *clp,dfprintk (MOUNT ," cleanup mode enabled\n" );set_bit (NFS_SP4_MACH_CRED_CLEANUP , &clp->cl_sp4_flags); } + +if (test_bit (OP_SECINFO , sp->allow.u.longs) && +test_bit (OP_SECINFO_NO_NAME , sp->allow.u.longs)) { +dfprintk (MOUNT ," secinfo mode enabled\n" ); +set_bit (NFS_SP4_MACH_CRED_SECINFO , &clp->cl_sp4_flags); + } }return 0 ;
include/linux/nfs_fs_sb.h +1 -0
@@ -92,6 +92,7 @@ struct nfs_client {#define NFS_SP4_MACH_CRED_MINIMAL 1/* Minimal sp4_mach_cred - state ops * must use machine cred */ #define NFS_SP4_MACH_CRED_CLEANUP 2/* CLOSE and LOCKU */ +#define NFS_SP4_MACH_CRED_SECINFO 3/* SECINFO and SECINFO_NO_NAME */ #endif /* CONFIG_NFS_V4 */ #ifdef CONFIG_NFS_FSCACHE
Signature · 1 line
1.7.12.4 (Apple Git-37)
PATCH 5/7 nfs4.1: Add SP4_MACH_CRED stateid support
In reply to Weston Andros AdamsonTEST_STATEID and FREE_STATEID can use the machine credential.
--- fs/nfs/nfs4proc.c | 19 +++++++++++++++++-- include/linux/nfs_fs_sb.h | 1 + 2 files changed, 18 insertions(+), 2 deletions(-)
fs/nfs/nfs4proc.c +17 -2
@@ -5945,7 +5945,9 @@ static const struct nfs41_state_protection nfs4_sp4_mach_cred_request = { [0 ] =1 << (OP_CLOSE ) | 1 << (OP_LOCKU), [1 ] =1 << (OP_SECINFO -32 ) | - 1 << (OP_SECINFO_NO_NAME - 32) +1 << (OP_SECINFO_NO_NAME -32 ) | +1 << (OP_TEST_STATEID -32 ) | + 1 << (OP_FREE_STATEID - 32) } };
@@ -6017,6 +6019,12 @@ static int nfs4_sp4_select_mode(struct nfs_client *clp,dfprintk (MOUNT ," secinfo mode enabled\n" );set_bit (NFS_SP4_MACH_CRED_SECINFO , &clp->cl_sp4_flags); } + +if (test_bit (OP_TEST_STATEID , sp->allow.u.longs) && +test_bit (OP_FREE_STATEID , sp->allow.u.longs)) { +dfprintk (MOUNT ," stateid mode enabled\n" ); +set_bit (NFS_SP4_MACH_CRED_STATEID , &clp->cl_sp4_flags); + } }return 0 ;
@@ -7337,11 +7345,15 @@ static int _nfs41_test_stateid(struct nfs_server *server, .rpc_resp = &res, .rpc_cred = cred, }; +struct rpc_clnt *rpc_client = server->client; + +nfs4_state_protect (server->nfs_client,NFS_SP4_MACH_CRED_STATEID , + &rpc_client, &msg);dprintk ("NFS call test_stateid %p\n" , stateid);nfs41_init_sequence (&args.seq_args, &res.seq_res,0 );nfs4_set_sequence_privileged (&args.seq_args); - status =nfs4_call_sync_sequence (server->client, server, &msg, + status =nfs4_call_sync_sequence (rpc_client, server, &msg, &args.seq_args, &res.seq_res);if (status !=NFS_OK ) {dprintk ("NFS reply test_stateid: failed, %d\n" , status);
@@ -7433,6 +7445,9 @@ static struct rpc_task *_nfs41_free_stateid(struct nfs_server *server, };struct nfs_free_stateid_data *data; +nfs4_state_protect (server->nfs_client,NFS_SP4_MACH_CRED_STATEID , + &task_setup.rpc_client, &msg); +dprintk ("NFS call free_stateid %p\n" , stateid); data =kmalloc (sizeof (*data),GFP_NOFS );if (!data)
include/linux/nfs_fs_sb.h +1 -0
@@ -93,6 +93,7 @@ struct nfs_client {* must use machine cred */ #define NFS_SP4_MACH_CRED_CLEANUP 2/* CLOSE and LOCKU */ #define NFS_SP4_MACH_CRED_SECINFO 3/* SECINFO and SECINFO_NO_NAME */ +#define NFS_SP4_MACH_CRED_STATEID 4/* TEST_STATEID and FREE_STATEID */ #endif /* CONFIG_NFS_V4 */ #ifdef CONFIG_NFS_FSCACHE
Signature · 1 line
1.7.12.4 (Apple Git-37)
PATCH 6/7 nfs4.1: Add SP4_MACH_CRED write and commit support
In reply to Weston Andros AdamsonWRITE and COMMIT can use the machine credential.
If WRITE is supported and COMMIT is not, make all (mach cred) writes FILE_SYNC4.
--- fs/nfs/nfs4_fs.h | 50 ++++++++++++++++++++++++++++++++++++++--------- fs/nfs/nfs4proc.c | 10 ++++++++++ fs/nfs/write.c | 6 ++++++ include/linux/nfs_fs_sb.h | 2 ++ 4 files changed, 59 insertions(+), 9 deletions(-)
fs/nfs/nfs4_fs.h +41 -9
@@ -273,15 +273,9 @@ is_ds_client(struct nfs_client *clp)return clp->cl_exchange_flags &EXCHGID4_FLAG_USE_PNFS_DS ; } -/* -* Function responsible for determining if an rpc_message should use the -* machine cred under SP4_MACH_CRED and if so switching the credential and -* authflavor (using the nfs_client's rpc_clnt which will be krb5i/p). -* Should be called before rpc_call_sync/rpc_call_async. -*/ -static inline void -nfs4_state_protect (struct nfs_client *clp,unsigned long sp4_mode, -struct rpc_clnt **clntp,struct rpc_message *msg) +static inline bool +_nfs4_state_protect (struct nfs_client *clp,unsigned long sp4_mode, +struct rpc_clnt **clntp,struct rpc_message *msg) {struct rpc_cred *newcred =NULL ;rpc_authflavor_t flavor;
@@ -299,7 +293,37 @@ nfs4_state_protect(struct nfs_client *clp, unsigned long sp4_mode,WARN_ON (flavor !=RPC_AUTH_GSS_KRB5I && flavor !=RPC_AUTH_GSS_KRB5P ); *clntp = clp->cl_rpcclient; + + return true; } +return false; +} + +/* +* Function responsible for determining if an rpc_message should use the +* machine cred under SP4_MACH_CRED and if so switching the credential and +* authflavor (using the nfs_client's rpc_clnt which will be krb5i/p). +* Should be called before rpc_call_sync/rpc_call_async. +*/ +static inline void +nfs4_state_protect (struct nfs_client *clp,unsigned long sp4_mode, +struct rpc_clnt **clntp,struct rpc_message *msg) +{ +_nfs4_state_protect (clp, sp4_mode, clntp, msg); +} + +/* +* Special wrapper to nfs4_state_protect for write. +* If WRITE can use machine cred but COMMIT cannot, make sure all writes +* that use machine cred use NFS_FILE_SYNC. +*/ +static inline void +nfs4_state_protect_write (struct nfs_client *clp,struct rpc_clnt **clntp, +struct rpc_message *msg,struct nfs_write_data *wdata) +{ +if (_nfs4_state_protect (clp,NFS_SP4_MACH_CRED_WRITE , clntp, msg) && + !test_bit (NFS_SP4_MACH_CRED_COMMIT , &clp->cl_sp4_flags)) + wdata->args.stable =NFS_FILE_SYNC ; }#else /* CONFIG_NFS_v4_1 */ static inline struct nfs4_session *nfs4_get_session (const struct nfs_server *server)
@@ -332,6 +356,12 @@ nfs4_state_protect(struct nfs_client *clp, unsigned long sp4_flags, struct rpc_clnt **clntp, struct rpc_message *msg) { } + +static inline void +nfs4_state_protect_write (struct nfs_client *clp,struct rpc_clnt **clntp, +struct rpc_message *msg,struct nfs_write_data *wdata) +{ +}#endif /* CONFIG_NFS_V4_1 */ extern const struct nfs4_minor_version_ops *nfs_v4_minor_ops[];
@@ -462,6 +492,8 @@ static inline bool nfs4_valid_open_stateid(const struct nfs4_state *state)#define nfs4_close_state (a, b) do { } while (0)#define nfs4_close_sync (a, b) do { } while (0) +#define nfs4_state_protect (a, b, c, d) do { } while (0) +#define nfs4_state_protect_write (a, b, c, d) do { } while (0)#endif /* CONFIG_NFS_V4 */ #endif /* __LINUX_FS_NFS_NFS4_FS.H */
fs/nfs/nfs4proc.c +10 -0
@@ -6025,6 +6025,16 @@ static int nfs4_sp4_select_mode(struct nfs_client *clp,dfprintk (MOUNT ," stateid mode enabled\n" );set_bit (NFS_SP4_MACH_CRED_STATEID , &clp->cl_sp4_flags); } + +if (test_bit (OP_WRITE , sp->allow.u.longs)) { +dfprintk (MOUNT ," write mode enabled\n" ); +set_bit (NFS_SP4_MACH_CRED_WRITE , &clp->cl_sp4_flags); + } + +if (test_bit (OP_COMMIT , sp->allow.u.longs)) { +dfprintk (MOUNT ," commit mode enabled\n" ); +set_bit (NFS_SP4_MACH_CRED_COMMIT , &clp->cl_sp4_flags); + } }return 0 ;
fs/nfs/write.c +6 -0
@@ -993,6 +993,9 @@ int nfs_initiate_write(struct rpc_clnt *clnt, data->args.count, (unsigned long long)data->args.offset); +nfs4_state_protect_write (NFS_SERVER (inode)->nfs_client, + &task_setup_data.rpc_client, &msg, data); + task =rpc_run_task (&task_setup_data);if (IS_ERR (task)) { ret =PTR_ERR (task);
@@ -1458,6 +1461,9 @@ int nfs_initiate_commit(struct rpc_clnt *clnt, struct nfs_commit_data *data,dprintk ("NFS: %5u initiated commit call\n" , data->task.tk_pid); +nfs4_state_protect (NFS_SERVER (data->inode)->nfs_client, +NFS_SP4_MACH_CRED_COMMIT , &task_setup_data.rpc_client, &msg); + task =rpc_run_task (&task_setup_data);if (IS_ERR (task))return PTR_ERR (task);
include/linux/nfs_fs_sb.h +2 -0
@@ -94,6 +94,8 @@ struct nfs_client {#define NFS_SP4_MACH_CRED_CLEANUP 2/* CLOSE and LOCKU */ #define NFS_SP4_MACH_CRED_SECINFO 3/* SECINFO and SECINFO_NO_NAME */ #define NFS_SP4_MACH_CRED_STATEID 4/* TEST_STATEID and FREE_STATEID */ +#define NFS_SP4_MACH_CRED_WRITE 5/* WRITE */ +#define NFS_SP4_MACH_CRED_COMMIT 6/* COMMIT */ #endif /* CONFIG_NFS_V4 */ #ifdef CONFIG_NFS_FSCACHE
Signature · 1 line
1.7.12.4 (Apple Git-37)
PATCH 7/7 nfs4: Map NFS4ERR_WRONG_CRED to EPERM
In reply to Weston Andros Adamson--- fs/nfs/nfs4proc.c | 1 + 1 file changed, 1 insertion(+)
fs/nfs/nfs4proc.c +1 -0
@@ -150,6 +150,7 @@ static int nfs4_map_errors(int err)case -NFS4ERR_RECALLCONFLICT :return -EREMOTEIO ;case -NFS4ERR_WRONGSEC : +case -NFS4ERR_WRONG_CRED :return -EPERM ;case -NFS4ERR_BADOWNER :case -NFS4ERR_BADNAME :
Signature · 1 line
1.7.12.4 (Apple Git-37)
Trond,
I think that these patches are missing put_rpccred() calls when we change rpc_message.
I'll add and repost…
-dros
Quoted 32 lines · Weston Andros Adamson
This is version 2 of this patchset including some cleanup, refactoring and fixes a few build issues with different configs.
I also added a few patches:
- WRITE and/or COMMIT support - tested on a hacked nfsd
- mapNFS4ERR_WRONG_CRED(an common SP4 error) to EPERMI meant to include a patch that only uses the machine cred (for 'allow' ops) when the user cred has expired, but after talking with Andy, I decided to wait for his cred expiration patchset to be merged as we'd be touching the same places and possibly duplicating effort.
Weston Andros Adamson (7):
nfs4.1: MinimalSP4_MACH_CREDimplementation nfs4.1: Add state protection handler nfs4.1: AddSP4_MACH_CREDcleanup support nfs4.1: AddSP4_MACH_CREDsecinfo support nfs4.1: AddSP4_MACH_CREDstateid support nfs4.1: AddSP4_MACH_CREDwrite and commit support
nfs4: MapNFS4ERR_WRONG_CREDto EPERMfs/nfs/nfs4_fs.h | 67 ++++++++++++++++ fs/nfs/nfs4proc.c | 191 ++++++++++++++++++++++++++++++++++++++++++++-- fs/nfs/nfs4xdr.c | 72 ++++++++++++++--- fs/nfs/write.c | 6 ++ include/linux/nfs_fs_sb.h | 9 +++ include/linux/nfs_xdr.h | 19 +++++ 6 files changed, 346 insertions(+), 18 deletions(-)Signature · 1 line
1.7.12.4 (Apple Git-37)