📄 nfs4state.c
字号:
clp->cl_clientid.cl_id = current_clientid++; }static voidgen_confirm(struct nfs4_client *clp) { struct timespec tv; u32 * p; tv = CURRENT_TIME; p = (u32 *)clp->cl_confirm.data; *p++ = tv.tv_sec; *p++ = tv.tv_nsec;}static intcheck_name(struct xdr_netobj name) { if (name.len == 0) return 0; if (name.len > NFS4_OPAQUE_LIMIT) { dprintk("NFSD: check_name: name too long(%d)!\n", name.len); return 0; } return 1;}static voidadd_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval){ unsigned int idhashval; list_add(&clp->cl_strhash, &unconf_str_hashtbl[strhashval]); idhashval = clientid_hashval(clp->cl_clientid.cl_id); list_add(&clp->cl_idhash, &unconf_id_hashtbl[idhashval]); list_add_tail(&clp->cl_lru, &client_lru); clp->cl_time = get_seconds();}static voidmove_to_confirmed(struct nfs4_client *clp){ unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); unsigned int strhashval; dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); list_del_init(&clp->cl_strhash); list_move(&clp->cl_idhash, &conf_id_hashtbl[idhashval]); strhashval = clientstr_hashval(clp->cl_recdir); list_add(&clp->cl_strhash, &conf_str_hashtbl[strhashval]); renew_client(clp);}static struct nfs4_client *find_confirmed_client(clientid_t *clid){ struct nfs4_client *clp; unsigned int idhashval = clientid_hashval(clid->cl_id); list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) { if (same_clid(&clp->cl_clientid, clid)) return clp; } return NULL;}static struct nfs4_client *find_unconfirmed_client(clientid_t *clid){ struct nfs4_client *clp; unsigned int idhashval = clientid_hashval(clid->cl_id); list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) { if (same_clid(&clp->cl_clientid, clid)) return clp; } return NULL;}static struct nfs4_client *find_confirmed_client_by_str(const char *dname, unsigned int hashval){ struct nfs4_client *clp; list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) { if (same_name(clp->cl_recdir, dname)) return clp; } return NULL;}static struct nfs4_client *find_unconfirmed_client_by_str(const char *dname, unsigned int hashval){ struct nfs4_client *clp; list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) { if (same_name(clp->cl_recdir, dname)) return clp; } return NULL;}/* a helper function for parse_callback */static intparse_octet(unsigned int *lenp, char **addrp){ unsigned int len = *lenp; char *p = *addrp; int n = -1; char c; for (;;) { if (!len) break; len--; c = *p++; if (c == '.') break; if ((c < '0') || (c > '9')) { n = -1; break; } if (n < 0) n = 0; n = (n * 10) + (c - '0'); if (n > 255) { n = -1; break; } } *lenp = len; *addrp = p; return n;}/* parse and set the setclientid ipv4 callback address */static intparse_ipv4(unsigned int addr_len, char *addr_val, unsigned int *cbaddrp, unsigned short *cbportp){ int temp = 0; u32 cbaddr = 0; u16 cbport = 0; u32 addrlen = addr_len; char *addr = addr_val; int i, shift; /* ipaddress */ shift = 24; for(i = 4; i > 0 ; i--) { if ((temp = parse_octet(&addrlen, &addr)) < 0) { return 0; } cbaddr |= (temp << shift); if (shift > 0) shift -= 8; } *cbaddrp = cbaddr; /* port */ shift = 8; for(i = 2; i > 0 ; i--) { if ((temp = parse_octet(&addrlen, &addr)) < 0) { return 0; } cbport |= (temp << shift); if (shift > 0) shift -= 8; } *cbportp = cbport; return 1;}static voidgen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se){ struct nfs4_callback *cb = &clp->cl_callback; /* Currently, we only support tcp for the callback channel */ if ((se->se_callback_netid_len != 3) || memcmp((char *)se->se_callback_netid_val, "tcp", 3)) goto out_err; if ( !(parse_ipv4(se->se_callback_addr_len, se->se_callback_addr_val, &cb->cb_addr, &cb->cb_port))) goto out_err; cb->cb_prog = se->se_callback_prog; cb->cb_ident = se->se_callback_ident; return;out_err: dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) " "will not receive delegations\n", clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); return;}/* * RFC 3010 has a complex implmentation description of processing a * SETCLIENTID request consisting of 5 bullets, labeled as * CASE0 - CASE4 below. * * NOTES: * callback information will be processed in a future patch * * an unconfirmed record is added when: * NORMAL (part of CASE 4): there is no confirmed nor unconfirmed record. * CASE 1: confirmed record found with matching name, principal, * verifier, and clientid. * CASE 2: confirmed record found with matching name, principal, * and there is no unconfirmed record with matching * name and principal * * an unconfirmed record is replaced when: * CASE 3: confirmed record found with matching name, principal, * and an unconfirmed record is found with matching * name, principal, and with clientid and * confirm that does not match the confirmed record. * CASE 4: there is no confirmed record with matching name and * principal. there is an unconfirmed record with * matching name, principal. * * an unconfirmed record is deleted when: * CASE 1: an unconfirmed record that matches input name, verifier, * and confirmed clientid. * CASE 4: any unconfirmed records with matching name and principal * that exist after an unconfirmed record has been replaced * as described above. * */__be32nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_setclientid *setclid){ struct sockaddr_in *sin = svc_addr_in(rqstp); struct xdr_netobj clname = { .len = setclid->se_namelen, .data = setclid->se_name, }; nfs4_verifier clverifier = setclid->se_verf; unsigned int strhashval; struct nfs4_client *conf, *unconf, *new; __be32 status; char dname[HEXDIR_LEN]; if (!check_name(clname)) return nfserr_inval; status = nfs4_make_rec_clidname(dname, &clname); if (status) return status; /* * XXX The Duplicate Request Cache (DRC) has been checked (??) * We get here on a DRC miss. */ strhashval = clientstr_hashval(dname); nfs4_lock_state(); conf = find_confirmed_client_by_str(dname, strhashval); if (conf) { /* * CASE 0: * clname match, confirmed, different principal * or different ip_address */ status = nfserr_clid_inuse; if (!same_creds(&conf->cl_cred, &rqstp->rq_cred) || conf->cl_addr != sin->sin_addr.s_addr) { dprintk("NFSD: setclientid: string in use by client" "at %u.%u.%u.%u\n", NIPQUAD(conf->cl_addr)); goto out; } } unconf = find_unconfirmed_client_by_str(dname, strhashval); status = nfserr_resource; if (!conf) { /* * CASE 4: * placed first, because it is the normal case. */ if (unconf) expire_client(unconf); new = create_client(clname, dname); if (new == NULL) goto out; gen_clid(new); } else if (same_verf(&conf->cl_verifier, &clverifier)) { /* * CASE 1: * cl_name match, confirmed, principal match * verifier match: probable callback update * * remove any unconfirmed nfs4_client with * matching cl_name, cl_verifier, and cl_clientid * * create and insert an unconfirmed nfs4_client with same * cl_name, cl_verifier, and cl_clientid as existing * nfs4_client, but with the new callback info and a * new cl_confirm */ if (unconf) { /* Note this is removing unconfirmed {*x***}, * which is stronger than RFC recommended {vxc**}. * This has the advantage that there is at most * one {*x***} in either list at any time. */ expire_client(unconf); } new = create_client(clname, dname); if (new == NULL) goto out; copy_clid(new, conf); } else if (!unconf) { /* * CASE 2: * clname match, confirmed, principal match * verfier does not match * no unconfirmed. create a new unconfirmed nfs4_client * using input clverifier, clname, and callback info * and generate a new cl_clientid and cl_confirm. */ new = create_client(clname, dname); if (new == NULL) goto out; gen_clid(new); } else if (!same_verf(&conf->cl_confirm, &unconf->cl_confirm)) { /* * CASE3: * confirmed found (name, principal match) * confirmed verifier does not match input clverifier * * unconfirmed found (name match) * confirmed->cl_confirm != unconfirmed->cl_confirm * * remove unconfirmed. * * create an unconfirmed nfs4_client * with same cl_name as existing confirmed nfs4_client, * but with new callback info, new cl_clientid, * new cl_verifier and a new cl_confirm */ expire_client(unconf); new = create_client(clname, dname); if (new == NULL) goto out; gen_clid(new); } else { /* No cases hit !!! */ status = nfserr_inval; goto out; } copy_verf(new, &clverifier); new->cl_addr = sin->sin_addr.s_addr; copy_cred(&new->cl_cred, &rqstp->rq_cred); gen_confirm(new); gen_callback(new, setclid); add_to_unconfirmed(new, strhashval); setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; setclid->se_clientid.cl_id = new->cl_clientid.cl_id; memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data)); status = nfs_ok;out: nfs4_unlock_state(); return status;}/* * RFC 3010 has a complex implmentation description of processing a * SETCLIENTID_CONFIRM request consisting of 4 bullets describing * processing on a DRC miss, labeled as CASE1 - CASE4 below. * * NOTE: callback information will be processed here in a future patch */__be32nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_setclientid_confirm *setclientid_confirm){ struct sockaddr_in *sin = svc_addr_in(rqstp); struct nfs4_client *conf, *unconf; nfs4_verifier confirm = setclientid_confirm->sc_confirm; clientid_t * clid = &setclientid_confirm->sc_clientid; __be32 status; if (STALE_CLIENTID(clid)) return nfserr_stale_clientid; /* * XXX The Duplicate Request Cache (DRC) has been checked (??) * We get here on a DRC miss. */ nfs4_lock_state(); conf = find_confirmed_client(clid); unconf = find_unconfirmed_client(clid); status = nfserr_clid_inuse; if (conf && conf->cl_addr != sin->sin_addr.s_addr) goto out; if (unconf && unconf->cl_addr != sin->sin_addr.s_addr) goto out; if ((conf && unconf) && (same_verf(&unconf->cl_confirm, &confirm)) && (same_verf(&conf->cl_verifier, &unconf->cl_verifier)) && (same_name(conf->cl_recdir,unconf->cl_recdir)) && (!same_verf(&conf->cl_confirm, &unconf->cl_confirm))) { /* CASE 1: * unconf record that matches input clientid and input confirm. * conf record that matches input clientid. * conf and unconf records match names, verifiers */ if (!same_creds(&conf->cl_cred, &unconf->cl_cred)) status = nfserr_clid_inuse; else { /* XXX: We just turn off callbacks until we can handle * change request correctly. */ atomic_set(&conf->cl_callback.cb_set, 0); gen_confirm(conf); nfsd4_remove_clid_dir(unconf); expire_client(unconf); status = nfs_ok; } } else if ((conf && !unconf) || ((conf && unconf) && (!same_verf(&conf->cl_verifier, &unconf->cl_verifier) || !same_name(conf->cl_recdir, unconf->cl_recdir)))) { /* CASE 2: * conf record that matches input clientid. * if unconf record matches input clientid, then * unconf->cl_name or unconf->cl_verifier don't match the * conf record. */ if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) status = nfserr_clid_inuse; else status = nfs_ok; } else if (!conf && unconf && same_verf(&unconf->cl_confirm, &confirm)) { /* CASE 3: * conf record not found. * unconf record found. * unconf->cl_confirm matches input confirm */ if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred)) { status = nfserr_clid_inuse; } else { unsigned int hash = clientstr_hashval(unconf->cl_recdir); conf = find_confirmed_client_by_str(unconf->cl_recdir, hash); if (conf) { nfsd4_remove_clid_dir(conf); expire_client(conf); } move_to_confirmed(unconf); conf = unconf; status = nfs_ok; } } else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm))) && (!unconf || (unconf && !same_verf(&unconf->cl_confirm, &confirm)))) { /* CASE 4: * conf record not found, or if conf, conf->cl_confirm does not * match input confirm. * unconf record not found, or if unconf, unconf->cl_confirm * does not match input confirm. */ status = nfserr_stale_clientid; } else { /* check that we have hit one of the cases...*/ status = nfserr_clid_inuse; }out: if (!status) nfsd4_probe_callback(conf); nfs4_unlock_state(); return status;}/* OPEN Share state helper functions */static inline struct nfs4_file *alloc_init_file(struct inode *ino){ struct nfs4_file *fp; unsigned int hashval = file_hashval(ino);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -