nfs4state.c
字号:
if (!check_name(clname)) goto out; /* * XXX The Duplicate Request Cache (DRC) has been checked (??) * We get here on a DRC miss. */ strhashval = clientstr_hashval(clname.data, clname.len); conf = NULL; nfs4_lock_state(); list_for_each_entry(clp, &conf_str_hashtbl[strhashval], cl_strhash) { if (!cmp_name(&clp->cl_name, &clname)) continue; /* * CASE 0: * clname match, confirmed, different principal * or different ip_address */ status = nfserr_clid_inuse; if (!cmp_creds(&clp->cl_cred,&rqstp->rq_cred)) { printk("NFSD: setclientid: string in use by client" "(clientid %08x/%08x)\n", clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); goto out; } if (clp->cl_addr != ip_addr) { printk("NFSD: setclientid: string in use by client" "(clientid %08x/%08x)\n", clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); goto out; } /* * cl_name match from a previous SETCLIENTID operation * XXX check for additional matches? */ conf = clp; break; } unconf = NULL; list_for_each_entry(clp, &unconf_str_hashtbl[strhashval], cl_strhash) { if (!cmp_name(&clp->cl_name, &clname)) continue; /* cl_name match from a previous SETCLIENTID operation */ unconf = clp; break; } status = nfserr_resource; if (!conf) { /* * CASE 4: * placed first, because it is the normal case. */ if (unconf) expire_client(unconf); if (!(new = create_client(clname))) goto out; copy_verf(new, &clverifier); new->cl_addr = ip_addr; copy_cred(&new->cl_cred,&rqstp->rq_cred); gen_clid(new); gen_confirm(new); gen_callback(new, setclid); add_to_unconfirmed(new, strhashval); } else if (cmp_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) && cmp_verf(&unconf->cl_verifier, &conf->cl_verifier) && cmp_clid(&unconf->cl_clientid, &conf->cl_clientid)) { expire_client(unconf); } if (!(new = create_client(clname))) goto out; copy_verf(new,&conf->cl_verifier); new->cl_addr = ip_addr; copy_cred(&new->cl_cred,&rqstp->rq_cred); copy_clid(new, conf); gen_confirm(new); gen_callback(new, setclid); add_to_unconfirmed(new,strhashval); } 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. */ if (!(new = create_client(clname))) goto out; copy_verf(new,&clverifier); new->cl_addr = ip_addr; copy_cred(&new->cl_cred,&rqstp->rq_cred); gen_clid(new); gen_confirm(new); gen_callback(new, setclid); add_to_unconfirmed(new, strhashval); } else if (!cmp_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); if (!(new = create_client(clname))) goto out; copy_verf(new,&clverifier); new->cl_addr = ip_addr; copy_cred(&new->cl_cred,&rqstp->rq_cred); gen_clid(new); gen_confirm(new); gen_callback(new, setclid); add_to_unconfirmed(new, strhashval); } else { /* No cases hit !!! */ status = nfserr_inval; goto out; } 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 */intnfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm){ u32 ip_addr = rqstp->rq_addr.sin_addr.s_addr; unsigned int idhashval; struct nfs4_client *clp, *conf = NULL, *unconf = NULL; nfs4_verifier confirm = setclientid_confirm->sc_confirm; clientid_t * clid = &setclientid_confirm->sc_clientid; int status; status = nfserr_stale_clientid; if (STALE_CLIENTID(clid)) goto out; /* * XXX The Duplicate Request Cache (DRC) has been checked (??) * We get here on a DRC miss. */ idhashval = clientid_hashval(clid->cl_id); nfs4_lock_state(); list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) { if (!cmp_clid(&clp->cl_clientid, clid)) continue; status = nfserr_inval; /* * Found a record for this clientid. If the IP addresses * don't match, return ERR_INVAL just as if the record had * not been found. */ if (clp->cl_addr != ip_addr) { printk("NFSD: setclientid: string in use by client" "(clientid %08x/%08x)\n", clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); goto out; } conf = clp; break; } list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) { if (!cmp_clid(&clp->cl_clientid, clid)) continue; status = nfserr_inval; if (clp->cl_addr != ip_addr) { printk("NFSD: setclientid: string in use by client" "(clientid %08x/%08x)\n", clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); goto out; } unconf = clp; break; } /* 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 ((conf && unconf) && (cmp_verf(&unconf->cl_confirm, &confirm)) && (cmp_verf(&conf->cl_verifier, &unconf->cl_verifier)) && (cmp_name(&conf->cl_name,&unconf->cl_name)) && (!cmp_verf(&conf->cl_confirm, &unconf->cl_confirm))) { if (!cmp_creds(&conf->cl_cred, &unconf->cl_cred)) status = nfserr_clid_inuse; else { expire_client(conf); move_to_confirmed(unconf, idhashval); status = nfs_ok; } goto out; } /* CASE 2: * conf record that matches input clientid. * if unconf record that matches input clientid, then unconf->cl_name * or unconf->cl_verifier don't match the conf record. */ if ((conf && !unconf) || ((conf && unconf) && (!cmp_verf(&conf->cl_verifier, &unconf->cl_verifier) || !cmp_name(&conf->cl_name, &unconf->cl_name)))) { if (!cmp_creds(&conf->cl_cred,&rqstp->rq_cred)) { status = nfserr_clid_inuse; } else { status = nfs_ok; } goto out; } /* CASE 3: * conf record not found. * unconf record found. * unconf->cl_confirm matches input confirm */ if (!conf && unconf && cmp_verf(&unconf->cl_confirm, &confirm)) { if (!cmp_creds(&unconf->cl_cred, &rqstp->rq_cred)) { status = nfserr_clid_inuse; } else { status = nfs_ok; move_to_confirmed(unconf, idhashval); } goto out; } /* CASE 4: * conf record not found, or if conf, then conf->cl_confirm does not * match input confirm. * unconf record not found, or if unconf, then unconf->cl_confirm * does not match input confirm. */ if ((!conf || (conf && !cmp_verf(&conf->cl_confirm, &confirm))) && (!unconf || (unconf && !cmp_verf(&unconf->cl_confirm, &confirm)))) { status = nfserr_stale_clientid; goto out; } /* check that we have hit one of the cases...*/ status = nfserr_inval; goto out;out: /* XXX if status == nfs_ok, probe callback path */ nfs4_unlock_state(); return status;}/* * Open owner state (share locks) *//* hash tables for nfs4_stateowner */#define OWNER_HASH_BITS 8#define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS)#define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1)#define ownerid_hashval(id) \ ((id) & OWNER_HASH_MASK)#define ownerstr_hashval(clientid, ownername) \ (((clientid) + opaque_hashval((ownername.data), (ownername.len))) & OWNER_HASH_MASK)static struct list_head ownerid_hashtbl[OWNER_HASH_SIZE];static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE];/* hash table for nfs4_file */#define FILE_HASH_BITS 8#define FILE_HASH_SIZE (1 << FILE_HASH_BITS)#define FILE_HASH_MASK (FILE_HASH_SIZE - 1)/* hash table for (open)nfs4_stateid */#define STATEID_HASH_BITS 10#define STATEID_HASH_SIZE (1 << STATEID_HASH_BITS)#define STATEID_HASH_MASK (STATEID_HASH_SIZE - 1)#define file_hashval(x) \ hash_ptr(x, FILE_HASH_BITS)#define stateid_hashval(owner_id, file_id) \ (((owner_id) + (file_id)) & STATEID_HASH_MASK)static struct list_head file_hashtbl[FILE_HASH_SIZE];static struct list_head stateid_hashtbl[STATEID_HASH_SIZE];/* OPEN Share state helper functions */static inline struct nfs4_file *alloc_init_file(unsigned int hashval, struct inode *ino) { struct nfs4_file *fp; if ((fp = kmalloc(sizeof(struct nfs4_file),GFP_KERNEL))) { INIT_LIST_HEAD(&fp->fi_hash); INIT_LIST_HEAD(&fp->fi_perfile); list_add(&fp->fi_hash, &file_hashtbl[hashval]); fp->fi_inode = igrab(ino); fp->fi_id = current_fileid++; alloc_file++; return fp; } return NULL;}static voidrelease_all_files(void){ int i; struct nfs4_file *fp; for (i=0;i<FILE_HASH_SIZE;i++) { while (!list_empty(&file_hashtbl[i])) { fp = list_entry(file_hashtbl[i].next, struct nfs4_file, fi_hash); /* this should never be more than once... */ if (!list_empty(&fp->fi_perfile)) { printk("ERROR: release_all_files: file %p is open, creating dangling state !!!\n",fp); } release_file(fp); } }}static inline struct nfs4_stateowner *alloc_stateowner(struct xdr_netobj *owner){ struct nfs4_stateowner *sop; if ((sop = kmalloc(sizeof(struct nfs4_stateowner),GFP_KERNEL))) { if ((sop->so_owner.data = kmalloc(owner->len, GFP_KERNEL))) { memcpy(sop->so_owner.data, owner->data, owner->len); sop->so_owner.len = owner->len; return sop; } kfree(sop); } return NULL;}/* should use a slab cache */static voidfree_stateowner(struct nfs4_stateowner *sop) { if (sop) { kfree(sop->so_owner.data); kfree(sop); sop = NULL; free_sowner++; }}static struct nfs4_stateowner *alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfsd4_open *open) { struct nfs4_stateowner *sop; struct nfs4_replay *rp; unsigned int idhashval; if (!(sop = alloc_stateowner(&open->op_owner))) return NULL; idhashval = ownerid_hashval(current_ownerid); INIT_LIST_HEAD(&sop->so_idhash); INIT_LIST_HEAD(&sop->so_strhash); INIT_LIST_HEAD(&sop->so_perclient); INIT_LIST_HEAD(&sop->so_perfilestate); INIT_LIST_HEAD(&sop->so_perlockowner); /* not used */ INIT_LIST_HEAD(&sop->so_close_lru); sop->so_time = 0; list_add(&sop->so_idhash, &ownerid_hashtbl[idhashval]); list_add(&sop->so_strhash, &ownerstr_hashtbl[strhashval]); list_add(&sop->so_perclient, &clp->cl_perclient); add_perclient++; sop->so_is_open_owner = 1; sop->so_id = current_ownerid++; sop->so_client = clp; sop->so_seqid = open->op_seqid; sop->so_confirmed = 0; rp = &sop->so_replay; rp->rp_status = NFSERR_SERVERFAULT; rp->rp_buflen = 0; rp->rp_buf = rp->rp_ibuf; alloc_sowner++; return sop;}static voidrelease_stateid_lockowner(struct nfs4_stateid *open_stp){ struct nfs4_stateowner *lock_sop; while (!list_empty(&open_stp->st_perlockowner)) { lock_sop = list_entry(open_stp->st_perlockowner.next, struct nfs4_stateowner, so_perlockowner); /* list_del(&open_stp->st_perlockowner); */ BUG_ON(lock_sop->so_is_open_owner); release_stateowner(lock_sop); }}static voidunhash_stateowner(struct nfs4_stateowner *sop){ struct nfs4_stateid *stp; list_del(&sop->so_idhash); list_del(&sop->so_strhash); list_del(&sop->so_perclient); list_del(&sop->so_perlockowner); del_perclient++; while (!list_empty(&sop->so_perfilestate)) { stp = list_entry(sop->so_perfilestate.next, struct nfs4_stateid, st_perfilestate); if (sop->so_is_open_owner) release_stateid(stp, OPEN_STATE); else release_stateid(stp, LOCK_STATE); }}static voidrelease_stateowner(struct nfs4_stateowner *sop){ unhash_stateowner(sop); list_del(&sop->so_close_lru); free_stateowner(sop);}static inline voidinit_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfs4_stateowner *sop, struct nfsd4_open *open) { unsigned int hashval = stateid_hashval(sop->so_id, fp->fi_id); INIT_LIST_HEAD(&stp->st_hash); INIT_LIST_HEAD(&stp->st_perfilestate); INIT_LIST_HEAD(&stp->st_perlockowner); INIT_LIST_HEAD(&stp->st_perfile); list_add(&stp->st_hash, &stateid_hashtbl[hashval]); list_add(&stp->st_perfilestate, &sop->so_perfilestate); list_add_perfile++; list_add(&stp->st_perfile, &fp->fi_perfile); stp->st_stateowner = sop; stp->st_file = fp; stp->st_stateid.si_boot = boot_time; stp->st_stateid.si_stateownerid = sop->so_id; stp->st_stateid.si_fileid = fp->fi_id; stp->st_stateid.si_generation = 0; stp->st_access_bmap = 0; stp->st_deny_bmap = 0; __set_bit(open->op_share_access, &stp->st_access_bmap); __set_bit(open->op_share_deny, &stp->st_deny_bmap);}static voidrelease_stateid(struct nfs4_stateid *stp, int flags) { list_del(&stp->st_hash); list_del_perfile++; list_del(&stp->st_perfile); list_del(&stp->st_perfilestate); if ((stp->st_vfs_set) && (flags & OPEN_STATE)) { release_stateid_lockowner(stp);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -