X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fnfsd%2Fexport.c;fp=fs%2Fnfsd%2Fexport.c;h=417ec02df44f33145504eabd72c940ea6efb3662;hb=64ba3f394c830ec48a1c31b53dcae312c56f1604;hp=01bc68c628ad16b92f84ce183e9cf908e09511c3;hpb=be1e6109ac94a859551f8e1774eb9a8469fe055c;p=linux-2.6.git diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 01bc68c62..417ec02df 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -57,17 +57,27 @@ static int exp_verify_string(char *cp, int max); #define EXPKEY_HASHMASK (EXPKEY_HASHMAX -1) static struct cache_head *expkey_table[EXPKEY_HASHMAX]; -static void expkey_put(struct kref *ref) +static inline int svc_expkey_hash(struct svc_expkey *item) { - struct svc_expkey *key = container_of(ref, struct svc_expkey, h.ref); + int hash = item->ek_fsidtype; + char * cp = (char*)item->ek_fsid; + int len = key_len(item->ek_fsidtype); - if (test_bit(CACHE_VALID, &key->h.flags) && - !test_bit(CACHE_NEGATIVE, &key->h.flags)) { - dput(key->ek_dentry); - mntput(key->ek_mnt); + hash ^= hash_mem(cp, len, EXPKEY_HASHBITS); + hash ^= hash_ptr(item->ek_client, EXPKEY_HASHBITS); + return hash & EXPKEY_HASHMASK; +} + +void expkey_put(struct cache_head *item, struct cache_detail *cd) +{ + if (cache_put(item, cd)) { + struct svc_expkey *key = container_of(item, struct svc_expkey, h); + if (test_bit(CACHE_VALID, &item->flags) && + !test_bit(CACHE_NEGATIVE, &item->flags)) + exp_put(key->ek_export); + auth_domain_put(key->ek_client); + kfree(key); } - auth_domain_put(key->ek_client); - kfree(key); } static void expkey_request(struct cache_detail *cd, @@ -85,10 +95,7 @@ static void expkey_request(struct cache_detail *cd, (*bpp)[-1] = '\n'; } -static struct svc_expkey *svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old); -static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *); -static struct cache_detail svc_expkey_cache; - +static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *, int); static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) { /* client fsidtype fsid [path] */ @@ -99,7 +106,6 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) int fsidtype; char *ep; struct svc_expkey key; - struct svc_expkey *ek; if (mesg[mlen-1] != '\n') return -EINVAL; @@ -126,7 +132,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) if (*ep) goto out; dprintk("found fsidtype %d\n", fsidtype); - if (key_len(fsidtype)==0) /* invalid type */ + if (fsidtype > 2) goto out; if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0) goto out; @@ -144,38 +150,40 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) key.ek_fsidtype = fsidtype; memcpy(key.ek_fsid, buf, len); - ek = svc_expkey_lookup(&key); - err = -ENOMEM; - if (!ek) - goto out; - /* now we want a pathname, or empty meaning NEGATIVE */ - err = -EINVAL; if ((len=qword_get(&mesg, buf, PAGE_SIZE)) < 0) goto out; dprintk("Path seems to be <%s>\n", buf); err = 0; if (len == 0) { + struct svc_expkey *ek; set_bit(CACHE_NEGATIVE, &key.h.flags); - ek = svc_expkey_update(&key, ek); + ek = svc_expkey_lookup(&key, 1); if (ek) - cache_put(&ek->h, &svc_expkey_cache); - else err = -ENOMEM; + expkey_put(&ek->h, &svc_expkey_cache); } else { struct nameidata nd; + struct svc_expkey *ek; + struct svc_export *exp; err = path_lookup(buf, 0, &nd); if (err) goto out; dprintk("Found the path %s\n", buf); - key.ek_mnt = nd.mnt; - key.ek_dentry = nd.dentry; + exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL); + + err = -ENOENT; + if (!exp) + goto out_nd; + key.ek_export = exp; + dprintk("And found export\n"); - ek = svc_expkey_update(&key, ek); + ek = svc_expkey_lookup(&key, 1); if (ek) - cache_put(&ek->h, &svc_expkey_cache); - else - err = -ENOMEM; + expkey_put(&ek->h, &svc_expkey_cache); + exp_put(exp); + err = 0; + out_nd: path_release(&nd); } cache_flush(); @@ -206,58 +214,13 @@ static int expkey_show(struct seq_file *m, if (test_bit(CACHE_VALID, &h->flags) && !test_bit(CACHE_NEGATIVE, &h->flags)) { seq_printf(m, " "); - seq_path(m, ek->ek_mnt, ek->ek_dentry, "\\ \t\n"); + seq_path(m, ek->ek_export->ex_mnt, ek->ek_export->ex_dentry, "\\ \t\n"); } seq_printf(m, "\n"); return 0; } - -static inline int expkey_match (struct cache_head *a, struct cache_head *b) -{ - struct svc_expkey *orig = container_of(a, struct svc_expkey, h); - struct svc_expkey *new = container_of(b, struct svc_expkey, h); - - if (orig->ek_fsidtype != new->ek_fsidtype || - orig->ek_client != new->ek_client || - memcmp(orig->ek_fsid, new->ek_fsid, key_len(orig->ek_fsidtype)) != 0) - return 0; - return 1; -} - -static inline void expkey_init(struct cache_head *cnew, - struct cache_head *citem) -{ - struct svc_expkey *new = container_of(cnew, struct svc_expkey, h); - struct svc_expkey *item = container_of(citem, struct svc_expkey, h); - - kref_get(&item->ek_client->ref); - new->ek_client = item->ek_client; - new->ek_fsidtype = item->ek_fsidtype; - new->ek_fsid[0] = item->ek_fsid[0]; - new->ek_fsid[1] = item->ek_fsid[1]; - new->ek_fsid[2] = item->ek_fsid[2]; -} - -static inline void expkey_update(struct cache_head *cnew, - struct cache_head *citem) -{ - struct svc_expkey *new = container_of(cnew, struct svc_expkey, h); - struct svc_expkey *item = container_of(citem, struct svc_expkey, h); - - new->ek_mnt = mntget(item->ek_mnt); - new->ek_dentry = dget(item->ek_dentry); -} - -static struct cache_head *expkey_alloc(void) -{ - struct svc_expkey *i = kmalloc(sizeof(*i), GFP_KERNEL); - if (i) - return &i->h; - else - return NULL; -} - -static struct cache_detail svc_expkey_cache = { + +struct cache_detail svc_expkey_cache = { .owner = THIS_MODULE, .hash_size = EXPKEY_HASHMAX, .hash_table = expkey_table, @@ -266,52 +229,34 @@ static struct cache_detail svc_expkey_cache = { .cache_request = expkey_request, .cache_parse = expkey_parse, .cache_show = expkey_show, - .match = expkey_match, - .init = expkey_init, - .update = expkey_update, - .alloc = expkey_alloc, }; -static struct svc_expkey * -svc_expkey_lookup(struct svc_expkey *item) +static inline int svc_expkey_match (struct svc_expkey *a, struct svc_expkey *b) { - struct cache_head *ch; - int hash = item->ek_fsidtype; - char * cp = (char*)item->ek_fsid; - int len = key_len(item->ek_fsidtype); - - hash ^= hash_mem(cp, len, EXPKEY_HASHBITS); - hash ^= hash_ptr(item->ek_client, EXPKEY_HASHBITS); - hash &= EXPKEY_HASHMASK; - - ch = sunrpc_cache_lookup(&svc_expkey_cache, &item->h, - hash); - if (ch) - return container_of(ch, struct svc_expkey, h); - else - return NULL; + if (a->ek_fsidtype != b->ek_fsidtype || + a->ek_client != b->ek_client || + memcmp(a->ek_fsid, b->ek_fsid, key_len(a->ek_fsidtype)) != 0) + return 0; + return 1; } -static struct svc_expkey * -svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old) +static inline void svc_expkey_init(struct svc_expkey *new, struct svc_expkey *item) { - struct cache_head *ch; - int hash = new->ek_fsidtype; - char * cp = (char*)new->ek_fsid; - int len = key_len(new->ek_fsidtype); - - hash ^= hash_mem(cp, len, EXPKEY_HASHBITS); - hash ^= hash_ptr(new->ek_client, EXPKEY_HASHBITS); - hash &= EXPKEY_HASHMASK; + cache_get(&item->ek_client->h); + new->ek_client = item->ek_client; + new->ek_fsidtype = item->ek_fsidtype; + new->ek_fsid[0] = item->ek_fsid[0]; + new->ek_fsid[1] = item->ek_fsid[1]; + new->ek_fsid[2] = item->ek_fsid[2]; +} - ch = sunrpc_cache_update(&svc_expkey_cache, &new->h, - &old->h, hash); - if (ch) - return container_of(ch, struct svc_expkey, h); - else - return NULL; +static inline void svc_expkey_update(struct svc_expkey *new, struct svc_expkey *item) +{ + cache_get(&item->ek_export->h); + new->ek_export = item->ek_export; } +static DefineSimpleCacheLookup(svc_expkey,0) /* no inplace updates */ #define EXPORT_HASHBITS 8 #define EXPORT_HASHMAX (1<< EXPORT_HASHBITS) @@ -319,13 +264,25 @@ svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old) static struct cache_head *export_table[EXPORT_HASHMAX]; -static void svc_export_put(struct kref *ref) +static inline int svc_export_hash(struct svc_export *item) { - struct svc_export *exp = container_of(ref, struct svc_export, h.ref); - dput(exp->ex_dentry); - mntput(exp->ex_mnt); - auth_domain_put(exp->ex_client); - kfree(exp); + int rv; + + rv = hash_ptr(item->ex_client, EXPORT_HASHBITS); + rv ^= hash_ptr(item->ex_dentry, EXPORT_HASHBITS); + rv ^= hash_ptr(item->ex_mnt, EXPORT_HASHBITS); + return rv; +} + +void svc_export_put(struct cache_head *item, struct cache_detail *cd) +{ + if (cache_put(item, cd)) { + struct svc_export *exp = container_of(item, struct svc_export, h); + dput(exp->ex_dentry); + mntput(exp->ex_mnt); + auth_domain_put(exp->ex_client); + kfree(exp); + } } static void svc_export_request(struct cache_detail *cd, @@ -347,9 +304,7 @@ static void svc_export_request(struct cache_detail *cd, (*bpp)[-1] = '\n'; } -static struct svc_export *svc_export_update(struct svc_export *new, - struct svc_export *old); -static struct svc_export *svc_export_lookup(struct svc_export *); +static struct svc_export *svc_export_lookup(struct svc_export *, int); static int check_export(struct inode *inode, int flags) { @@ -422,7 +377,7 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0) goto out; err = path_lookup(buf, 0, &nd); - if (err) goto out_no_path; + if (err) goto out; exp.h.flags = 0; exp.ex_client = dom; @@ -462,20 +417,14 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) if (err) goto out; } - expp = svc_export_lookup(&exp); + expp = svc_export_lookup(&exp, 1); if (expp) - expp = svc_export_update(&exp, expp); - else - err = -ENOMEM; - cache_flush(); - if (expp == NULL) - err = -ENOMEM; - else exp_put(expp); + err = 0; + cache_flush(); out: if (nd.dentry) path_release(&nd); - out_no_path: if (dom) auth_domain_put(dom); kfree(buf); @@ -506,46 +455,6 @@ static int svc_export_show(struct seq_file *m, seq_puts(m, ")\n"); return 0; } -static int svc_export_match(struct cache_head *a, struct cache_head *b) -{ - struct svc_export *orig = container_of(a, struct svc_export, h); - struct svc_export *new = container_of(b, struct svc_export, h); - return orig->ex_client == new->ex_client && - orig->ex_dentry == new->ex_dentry && - orig->ex_mnt == new->ex_mnt; -} - -static void svc_export_init(struct cache_head *cnew, struct cache_head *citem) -{ - struct svc_export *new = container_of(cnew, struct svc_export, h); - struct svc_export *item = container_of(citem, struct svc_export, h); - - kref_get(&item->ex_client->ref); - new->ex_client = item->ex_client; - new->ex_dentry = dget(item->ex_dentry); - new->ex_mnt = mntget(item->ex_mnt); -} - -static void export_update(struct cache_head *cnew, struct cache_head *citem) -{ - struct svc_export *new = container_of(cnew, struct svc_export, h); - struct svc_export *item = container_of(citem, struct svc_export, h); - - new->ex_flags = item->ex_flags; - new->ex_anon_uid = item->ex_anon_uid; - new->ex_anon_gid = item->ex_anon_gid; - new->ex_fsid = item->ex_fsid; -} - -static struct cache_head *svc_export_alloc(void) -{ - struct svc_export *i = kmalloc(sizeof(*i), GFP_KERNEL); - if (i) - return &i->h; - else - return NULL; -} - struct cache_detail svc_export_cache = { .owner = THIS_MODULE, .hash_size = EXPORT_HASHMAX, @@ -555,49 +464,34 @@ struct cache_detail svc_export_cache = { .cache_request = svc_export_request, .cache_parse = svc_export_parse, .cache_show = svc_export_show, - .match = svc_export_match, - .init = svc_export_init, - .update = export_update, - .alloc = svc_export_alloc, }; -static struct svc_export * -svc_export_lookup(struct svc_export *exp) +static inline int svc_export_match(struct svc_export *a, struct svc_export *b) { - struct cache_head *ch; - int hash; - hash = hash_ptr(exp->ex_client, EXPORT_HASHBITS); - hash ^= hash_ptr(exp->ex_dentry, EXPORT_HASHBITS); - hash ^= hash_ptr(exp->ex_mnt, EXPORT_HASHBITS); - - ch = sunrpc_cache_lookup(&svc_export_cache, &exp->h, - hash); - if (ch) - return container_of(ch, struct svc_export, h); - else - return NULL; + return a->ex_client == b->ex_client && + a->ex_dentry == b->ex_dentry && + a->ex_mnt == b->ex_mnt; +} +static inline void svc_export_init(struct svc_export *new, struct svc_export *item) +{ + cache_get(&item->ex_client->h); + new->ex_client = item->ex_client; + new->ex_dentry = dget(item->ex_dentry); + new->ex_mnt = mntget(item->ex_mnt); } -static struct svc_export * -svc_export_update(struct svc_export *new, struct svc_export *old) +static inline void svc_export_update(struct svc_export *new, struct svc_export *item) { - struct cache_head *ch; - int hash; - hash = hash_ptr(old->ex_client, EXPORT_HASHBITS); - hash ^= hash_ptr(old->ex_dentry, EXPORT_HASHBITS); - hash ^= hash_ptr(old->ex_mnt, EXPORT_HASHBITS); - - ch = sunrpc_cache_update(&svc_export_cache, &new->h, - &old->h, - hash); - if (ch) - return container_of(ch, struct svc_export, h); - else - return NULL; + new->ex_flags = item->ex_flags; + new->ex_anon_uid = item->ex_anon_uid; + new->ex_anon_gid = item->ex_anon_gid; + new->ex_fsid = item->ex_fsid; } +static DefineSimpleCacheLookup(svc_export,1) /* allow inplace updates */ + -static struct svc_expkey * +struct svc_expkey * exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp) { struct svc_expkey key, *ek; @@ -610,7 +504,7 @@ exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp) key.ek_fsidtype = fsid_type; memcpy(key.ek_fsid, fsidv, key_len(fsid_type)); - ek = svc_expkey_lookup(&key); + ek = svc_expkey_lookup(&key, 0); if (ek != NULL) if ((err = cache_check(&svc_expkey_cache, &ek->h, reqp))) ek = ERR_PTR(err); @@ -625,16 +519,13 @@ static int exp_set_key(svc_client *clp, int fsid_type, u32 *fsidv, key.ek_client = clp; key.ek_fsidtype = fsid_type; memcpy(key.ek_fsid, fsidv, key_len(fsid_type)); - key.ek_mnt = exp->ex_mnt; - key.ek_dentry = exp->ex_dentry; + key.ek_export = exp; key.h.expiry_time = NEVER; key.h.flags = 0; - ek = svc_expkey_lookup(&key); - if (ek) - ek = svc_expkey_update(&key,ek); + ek = svc_expkey_lookup(&key, 1); if (ek) { - cache_put(&ek->h, &svc_expkey_cache); + expkey_put(&ek->h, &svc_expkey_cache); return 0; } return -ENOMEM; @@ -682,7 +573,7 @@ exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry, key.ex_mnt = mnt; key.ex_dentry = dentry; - exp = svc_export_lookup(&key); + exp = svc_export_lookup(&key, 0); if (exp != NULL) switch (cache_check(&svc_export_cache, &exp->h, reqp)) { case 0: break; @@ -763,7 +654,7 @@ static void exp_fsid_unhash(struct svc_export *exp) ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid); if (ek && !IS_ERR(ek)) { ek->h.expiry_time = get_seconds()-1; - cache_put(&ek->h, &svc_expkey_cache); + expkey_put(&ek->h, &svc_expkey_cache); } svc_expkey_cache.nextcheck = get_seconds(); } @@ -801,7 +692,7 @@ static void exp_unhash(struct svc_export *exp) ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino); if (ek && !IS_ERR(ek)) { ek->h.expiry_time = get_seconds()-1; - cache_put(&ek->h, &svc_expkey_cache); + expkey_put(&ek->h, &svc_expkey_cache); } svc_expkey_cache.nextcheck = get_seconds(); } @@ -850,8 +741,8 @@ exp_export(struct nfsctl_export *nxp) if ((nxp->ex_flags & NFSEXP_FSID) && (fsid_key = exp_get_fsid_key(clp, nxp->ex_dev)) && !IS_ERR(fsid_key) && - fsid_key->ek_mnt && - (fsid_key->ek_mnt != nd.mnt || fsid_key->ek_dentry != nd.dentry) ) + fsid_key->ek_export && + fsid_key->ek_export != exp) goto finish; if (exp) { @@ -884,13 +775,13 @@ exp_export(struct nfsctl_export *nxp) new.ex_anon_gid = nxp->ex_anon_gid; new.ex_fsid = nxp->ex_dev; - exp = svc_export_lookup(&new); - if (exp) - exp = svc_export_update(&new, exp); + exp = svc_export_lookup(&new, 1); - if (!exp) + if (exp == NULL) goto finish; + err = 0; + if (exp_hash(clp, exp) || exp_fsid_hash(clp, exp)) { /* failed to create at least one index */ @@ -903,7 +794,7 @@ finish: if (exp) exp_put(exp); if (fsid_key && !IS_ERR(fsid_key)) - cache_put(&fsid_key->h, &svc_expkey_cache); + expkey_put(&fsid_key->h, &svc_expkey_cache); if (clp) auth_domain_put(clp); path_release(&nd); @@ -1021,24 +912,6 @@ out: return err; } -struct svc_export * -exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv, - struct cache_req *reqp) -{ - struct svc_export *exp; - struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp); - if (!ek || IS_ERR(ek)) - return ERR_PTR(PTR_ERR(ek)); - - exp = exp_get_by_name(clp, ek->ek_mnt, ek->ek_dentry, reqp); - cache_put(&ek->h, &svc_expkey_cache); - - if (!exp || IS_ERR(exp)) - return ERR_PTR(PTR_ERR(exp)); - return exp; -} - - /* * Called when we need the filehandle for the root of the pseudofs, * for a given NFSv4 client. The root is defined to be the @@ -1049,7 +922,6 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp, struct cache_req *creq) { struct svc_expkey *fsid_key; - struct svc_export *exp; int rv; u32 fsidv[2]; @@ -1061,17 +933,9 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp, if (!fsid_key || IS_ERR(fsid_key)) return nfserr_perm; - exp = exp_get_by_name(clp, fsid_key->ek_mnt, fsid_key->ek_dentry, creq); - if (exp == NULL) - rv = nfserr_perm; - else if (IS_ERR(exp)) - rv = nfserrno(PTR_ERR(exp)); - else { - rv = fh_compose(fhp, exp, - fsid_key->ek_dentry, NULL); - exp_put(exp); - } - cache_put(&fsid_key->h, &svc_expkey_cache); + rv = fh_compose(fhp, fsid_key->ek_export, + fsid_key->ek_export->ex_dentry, NULL); + expkey_put(&fsid_key->h, &svc_expkey_cache); return rv; } @@ -1190,7 +1054,7 @@ static int e_show(struct seq_file *m, void *p) cache_get(&exp->h); if (cache_check(&svc_export_cache, &exp->h, NULL)) return 0; - cache_put(&exp->h, &svc_export_cache); + if (cache_put(&exp->h, &svc_export_cache)) BUG(); return svc_export_show(m, &svc_export_cache, cp); } @@ -1265,6 +1129,7 @@ exp_delclient(struct nfsctl_client *ncp) */ if (dom) { err = auth_unix_forget_old(dom); + dom->h.expiry_time = get_seconds(); auth_domain_put(dom); }