Loading fs/nfsd/nfs4proc.c +5 −0 Original line number Diff line number Diff line Loading @@ -1417,6 +1417,11 @@ static struct nfsd4_operation nfsd4_ops[] = { .op_flags = OP_HANDLES_WRONGSEC, .op_name = "OP_SECINFO_NO_NAME", }, [OP_FREE_STATEID] = { .op_func = (nfsd4op_func)nfsd4_free_stateid, .op_flags = ALLOWED_WITHOUT_FH, .op_name = "OP_FREE_STATEID", }, }; static const char *nfsd4_op_name(unsigned opnum) Loading fs/nfsd/nfs4state.c +118 −0 Original line number Diff line number Diff line Loading @@ -60,9 +60,12 @@ static u64 current_sessionid = 1; /* forward declarations */ static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags); static struct nfs4_stateid * search_for_stateid(stateid_t *stid); static struct nfs4_delegation * search_for_delegation(stateid_t *stid); static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid); static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; static void nfs4_set_recdir(char *recdir); static int check_for_locks(struct nfs4_file *filp, struct nfs4_stateowner *lowner); /* Locking: */ Loading Loading @@ -3137,6 +3140,11 @@ static int is_delegation_stateid(stateid_t *stateid) return stateid->si_fileid == 0; } static int is_open_stateid(struct nfs4_stateid *stateid) { return stateid->st_openstp == NULL; } /* * Checks for stateid operations */ Loading Loading @@ -3216,6 +3224,70 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, return status; } static __be32 nfsd4_free_delegation_stateid(stateid_t *stateid) { struct nfs4_delegation *dp = search_for_delegation(stateid); if (dp) return nfserr_locks_held; return nfserr_bad_stateid; } static __be32 nfsd4_free_lock_stateid(struct nfs4_stateid *stp) { if (check_for_locks(stp->st_file, stp->st_stateowner)) return nfserr_locks_held; release_lock_stateid(stp); return nfs_ok; } /* * Free a state id */ __be32 nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_free_stateid *free_stateid) { stateid_t *stateid = &free_stateid->fr_stateid; struct nfs4_stateid *stp; __be32 ret; nfs4_lock_state(); if (is_delegation_stateid(stateid)) { ret = nfsd4_free_delegation_stateid(stateid); goto out; } stp = search_for_stateid(stateid); if (!stp) { ret = nfserr_bad_stateid; goto out; } if (stateid->si_generation != 0) { if (stateid->si_generation < stp->st_stateid.si_generation) { ret = nfserr_old_stateid; goto out; } if (stateid->si_generation > stp->st_stateid.si_generation) { ret = nfserr_bad_stateid; goto out; } } if (is_open_stateid(stp)) { ret = nfserr_locks_held; goto out; } else { ret = nfsd4_free_lock_stateid(stp); goto out; } out: nfs4_unlock_state(); return ret; } static inline int setlkflg (int type) { Loading Loading @@ -3594,6 +3666,14 @@ static struct list_head lock_ownerid_hashtbl[LOCK_HASH_SIZE]; static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE]; static struct list_head lockstateid_hashtbl[STATEID_HASH_SIZE]; static int same_stateid(stateid_t *id_one, stateid_t *id_two) { if (id_one->si_stateownerid != id_two->si_stateownerid) return 0; return id_one->si_fileid == id_two->si_fileid; } static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags) { Loading Loading @@ -3623,6 +3703,44 @@ find_stateid(stateid_t *stid, int flags) return NULL; } static struct nfs4_stateid * search_for_stateid(stateid_t *stid) { struct nfs4_stateid *local; unsigned int hashval = stateid_hashval(stid->si_stateownerid, stid->si_fileid); list_for_each_entry(local, &lockstateid_hashtbl[hashval], st_hash) { if (same_stateid(&local->st_stateid, stid)) return local; } list_for_each_entry(local, &stateid_hashtbl[hashval], st_hash) { if (same_stateid(&local->st_stateid, stid)) return local; } return NULL; } static struct nfs4_delegation * search_for_delegation(stateid_t *stid) { struct nfs4_file *fp; struct nfs4_delegation *dp; struct list_head *pos; int i; for (i = 0; i < FILE_HASH_SIZE; i++) { list_for_each_entry(fp, &file_hashtbl[i], fi_hash) { list_for_each(pos, &fp->fi_delegations) { dp = list_entry(pos, struct nfs4_delegation, dl_perfile); if (same_stateid(&dp->dl_stateid, stid)) return dp; } } } return NULL; } static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid) { Loading fs/nfsd/nfs4xdr.c +30 −2 Original line number Diff line number Diff line Loading @@ -1245,6 +1245,19 @@ nfsd4_decode_destroy_session(struct nfsd4_compoundargs *argp, DECODE_TAIL; } static __be32 nfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_free_stateid *free_stateid) { DECODE_HEAD; READ_BUF(sizeof(stateid_t)); READ32(free_stateid->fr_stateid.si_generation); COPYMEM(&free_stateid->fr_stateid.si_opaque, sizeof(stateid_opaque_t)); DECODE_TAIL; } static __be32 nfsd4_decode_sequence(struct nfsd4_compoundargs *argp, struct nfsd4_sequence *seq) Loading Loading @@ -1370,7 +1383,7 @@ static nfsd4_dec nfsd41_dec_ops[] = { [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id, [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session, [OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session, [OP_FREE_STATEID] = (nfsd4_dec)nfsd4_decode_notsupp, [OP_FREE_STATEID] = (nfsd4_dec)nfsd4_decode_free_stateid, [OP_GET_DIR_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp, [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_notsupp, [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp, Loading Loading @@ -3115,6 +3128,21 @@ nfsd4_encode_destroy_session(struct nfsd4_compoundres *resp, int nfserr, return nfserr; } static __be32 nfsd4_encode_free_stateid(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_free_stateid *free_stateid) { __be32 *p; if (nfserr) return nfserr; RESERVE_SPACE(4); WRITE32(nfserr); ADJUST_ARGS(); return nfserr; } static __be32 nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_sequence *seq) Loading Loading @@ -3196,7 +3224,7 @@ static nfsd4_enc nfsd4_enc_ops[] = { [OP_EXCHANGE_ID] = (nfsd4_enc)nfsd4_encode_exchange_id, [OP_CREATE_SESSION] = (nfsd4_enc)nfsd4_encode_create_session, [OP_DESTROY_SESSION] = (nfsd4_enc)nfsd4_encode_destroy_session, [OP_FREE_STATEID] = (nfsd4_enc)nfsd4_encode_noop, [OP_FREE_STATEID] = (nfsd4_enc)nfsd4_encode_free_stateid, [OP_GET_DIR_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop, [OP_GETDEVICEINFO] = (nfsd4_enc)nfsd4_encode_noop, [OP_GETDEVICELIST] = (nfsd4_enc)nfsd4_encode_noop, Loading fs/nfsd/xdr4.h +8 −0 Original line number Diff line number Diff line Loading @@ -342,6 +342,11 @@ struct nfsd4_setclientid_confirm { nfs4_verifier sc_confirm; }; struct nfsd4_free_stateid { stateid_t fr_stateid; /* request */ __be32 fr_status; /* response */ }; /* also used for NVERIFY */ struct nfsd4_verify { u32 ve_bmval[3]; /* request */ Loading Loading @@ -432,6 +437,7 @@ struct nfsd4_op { struct nfsd4_destroy_session destroy_session; struct nfsd4_sequence sequence; struct nfsd4_reclaim_complete reclaim_complete; struct nfsd4_free_stateid free_stateid; } u; struct nfs4_replay * replay; }; Loading Loading @@ -564,6 +570,8 @@ extern __be32 nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *, struct nfsd4_delegreturn *dr); extern __be32 nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *, clientid_t *clid); extern __be32 nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *, struct nfsd4_free_stateid *free_stateid); #endif /* Loading Loading
fs/nfsd/nfs4proc.c +5 −0 Original line number Diff line number Diff line Loading @@ -1417,6 +1417,11 @@ static struct nfsd4_operation nfsd4_ops[] = { .op_flags = OP_HANDLES_WRONGSEC, .op_name = "OP_SECINFO_NO_NAME", }, [OP_FREE_STATEID] = { .op_func = (nfsd4op_func)nfsd4_free_stateid, .op_flags = ALLOWED_WITHOUT_FH, .op_name = "OP_FREE_STATEID", }, }; static const char *nfsd4_op_name(unsigned opnum) Loading
fs/nfsd/nfs4state.c +118 −0 Original line number Diff line number Diff line Loading @@ -60,9 +60,12 @@ static u64 current_sessionid = 1; /* forward declarations */ static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags); static struct nfs4_stateid * search_for_stateid(stateid_t *stid); static struct nfs4_delegation * search_for_delegation(stateid_t *stid); static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid); static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; static void nfs4_set_recdir(char *recdir); static int check_for_locks(struct nfs4_file *filp, struct nfs4_stateowner *lowner); /* Locking: */ Loading Loading @@ -3137,6 +3140,11 @@ static int is_delegation_stateid(stateid_t *stateid) return stateid->si_fileid == 0; } static int is_open_stateid(struct nfs4_stateid *stateid) { return stateid->st_openstp == NULL; } /* * Checks for stateid operations */ Loading Loading @@ -3216,6 +3224,70 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, return status; } static __be32 nfsd4_free_delegation_stateid(stateid_t *stateid) { struct nfs4_delegation *dp = search_for_delegation(stateid); if (dp) return nfserr_locks_held; return nfserr_bad_stateid; } static __be32 nfsd4_free_lock_stateid(struct nfs4_stateid *stp) { if (check_for_locks(stp->st_file, stp->st_stateowner)) return nfserr_locks_held; release_lock_stateid(stp); return nfs_ok; } /* * Free a state id */ __be32 nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_free_stateid *free_stateid) { stateid_t *stateid = &free_stateid->fr_stateid; struct nfs4_stateid *stp; __be32 ret; nfs4_lock_state(); if (is_delegation_stateid(stateid)) { ret = nfsd4_free_delegation_stateid(stateid); goto out; } stp = search_for_stateid(stateid); if (!stp) { ret = nfserr_bad_stateid; goto out; } if (stateid->si_generation != 0) { if (stateid->si_generation < stp->st_stateid.si_generation) { ret = nfserr_old_stateid; goto out; } if (stateid->si_generation > stp->st_stateid.si_generation) { ret = nfserr_bad_stateid; goto out; } } if (is_open_stateid(stp)) { ret = nfserr_locks_held; goto out; } else { ret = nfsd4_free_lock_stateid(stp); goto out; } out: nfs4_unlock_state(); return ret; } static inline int setlkflg (int type) { Loading Loading @@ -3594,6 +3666,14 @@ static struct list_head lock_ownerid_hashtbl[LOCK_HASH_SIZE]; static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE]; static struct list_head lockstateid_hashtbl[STATEID_HASH_SIZE]; static int same_stateid(stateid_t *id_one, stateid_t *id_two) { if (id_one->si_stateownerid != id_two->si_stateownerid) return 0; return id_one->si_fileid == id_two->si_fileid; } static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags) { Loading Loading @@ -3623,6 +3703,44 @@ find_stateid(stateid_t *stid, int flags) return NULL; } static struct nfs4_stateid * search_for_stateid(stateid_t *stid) { struct nfs4_stateid *local; unsigned int hashval = stateid_hashval(stid->si_stateownerid, stid->si_fileid); list_for_each_entry(local, &lockstateid_hashtbl[hashval], st_hash) { if (same_stateid(&local->st_stateid, stid)) return local; } list_for_each_entry(local, &stateid_hashtbl[hashval], st_hash) { if (same_stateid(&local->st_stateid, stid)) return local; } return NULL; } static struct nfs4_delegation * search_for_delegation(stateid_t *stid) { struct nfs4_file *fp; struct nfs4_delegation *dp; struct list_head *pos; int i; for (i = 0; i < FILE_HASH_SIZE; i++) { list_for_each_entry(fp, &file_hashtbl[i], fi_hash) { list_for_each(pos, &fp->fi_delegations) { dp = list_entry(pos, struct nfs4_delegation, dl_perfile); if (same_stateid(&dp->dl_stateid, stid)) return dp; } } } return NULL; } static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid) { Loading
fs/nfsd/nfs4xdr.c +30 −2 Original line number Diff line number Diff line Loading @@ -1245,6 +1245,19 @@ nfsd4_decode_destroy_session(struct nfsd4_compoundargs *argp, DECODE_TAIL; } static __be32 nfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_free_stateid *free_stateid) { DECODE_HEAD; READ_BUF(sizeof(stateid_t)); READ32(free_stateid->fr_stateid.si_generation); COPYMEM(&free_stateid->fr_stateid.si_opaque, sizeof(stateid_opaque_t)); DECODE_TAIL; } static __be32 nfsd4_decode_sequence(struct nfsd4_compoundargs *argp, struct nfsd4_sequence *seq) Loading Loading @@ -1370,7 +1383,7 @@ static nfsd4_dec nfsd41_dec_ops[] = { [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id, [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session, [OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session, [OP_FREE_STATEID] = (nfsd4_dec)nfsd4_decode_notsupp, [OP_FREE_STATEID] = (nfsd4_dec)nfsd4_decode_free_stateid, [OP_GET_DIR_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp, [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_notsupp, [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp, Loading Loading @@ -3115,6 +3128,21 @@ nfsd4_encode_destroy_session(struct nfsd4_compoundres *resp, int nfserr, return nfserr; } static __be32 nfsd4_encode_free_stateid(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_free_stateid *free_stateid) { __be32 *p; if (nfserr) return nfserr; RESERVE_SPACE(4); WRITE32(nfserr); ADJUST_ARGS(); return nfserr; } static __be32 nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_sequence *seq) Loading Loading @@ -3196,7 +3224,7 @@ static nfsd4_enc nfsd4_enc_ops[] = { [OP_EXCHANGE_ID] = (nfsd4_enc)nfsd4_encode_exchange_id, [OP_CREATE_SESSION] = (nfsd4_enc)nfsd4_encode_create_session, [OP_DESTROY_SESSION] = (nfsd4_enc)nfsd4_encode_destroy_session, [OP_FREE_STATEID] = (nfsd4_enc)nfsd4_encode_noop, [OP_FREE_STATEID] = (nfsd4_enc)nfsd4_encode_free_stateid, [OP_GET_DIR_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop, [OP_GETDEVICEINFO] = (nfsd4_enc)nfsd4_encode_noop, [OP_GETDEVICELIST] = (nfsd4_enc)nfsd4_encode_noop, Loading
fs/nfsd/xdr4.h +8 −0 Original line number Diff line number Diff line Loading @@ -342,6 +342,11 @@ struct nfsd4_setclientid_confirm { nfs4_verifier sc_confirm; }; struct nfsd4_free_stateid { stateid_t fr_stateid; /* request */ __be32 fr_status; /* response */ }; /* also used for NVERIFY */ struct nfsd4_verify { u32 ve_bmval[3]; /* request */ Loading Loading @@ -432,6 +437,7 @@ struct nfsd4_op { struct nfsd4_destroy_session destroy_session; struct nfsd4_sequence sequence; struct nfsd4_reclaim_complete reclaim_complete; struct nfsd4_free_stateid free_stateid; } u; struct nfs4_replay * replay; }; Loading Loading @@ -564,6 +570,8 @@ extern __be32 nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *, struct nfsd4_delegreturn *dr); extern __be32 nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *, clientid_t *clid); extern __be32 nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *, struct nfsd4_free_stateid *free_stateid); #endif /* Loading