📄 nfs4idmap.c
字号:
/* * fs/nfsd/nfs4idmap.c * * Mapping of UID/GIDs to name and vice versa. * * Copyright (c) 2002, 2003 The Regents of the University of * Michigan. All rights reserved. * * Marius Aamodt Eriksen <marius@umich.edu> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include <linux/module.h>#include <linux/init.h>#include <linux/mm.h>#include <linux/utsname.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/sunrpc/clnt.h>#include <linux/nfs.h>#include <linux/nfs4.h>#include <linux/nfs_fs.h>#include <linux/nfs_page.h>#include <linux/sunrpc/cache.h>#include <linux/nfsd_idmap.h>#include <linux/list.h>#include <linux/time.h>#include <linux/seq_file.h>#include <linux/sunrpc/svcauth.h>/* * Cache entry *//* * XXX we know that IDMAP_NAMESZ < PAGE_SIZE, but it's ugly to rely on * that. */#define IDMAP_TYPE_USER 0#define IDMAP_TYPE_GROUP 1struct ent { struct cache_head h; int type; /* User / Group */ uid_t id; char name[IDMAP_NAMESZ]; char authname[IDMAP_NAMESZ];};/* Common entry handling */#define ENT_HASHBITS 8#define ENT_HASHMAX (1 << ENT_HASHBITS)#define ENT_HASHMASK (ENT_HASHMAX - 1)static voident_init(struct cache_head *cnew, struct cache_head *citm){ struct ent *new = container_of(cnew, struct ent, h); struct ent *itm = container_of(citm, struct ent, h); new->id = itm->id; new->type = itm->type; strlcpy(new->name, itm->name, sizeof(new->name)); strlcpy(new->authname, itm->authname, sizeof(new->name));}static voident_put(struct kref *ref){ struct ent *map = container_of(ref, struct ent, h.ref); kfree(map);}static struct cache_head *ent_alloc(void){ struct ent *e = kmalloc(sizeof(*e), GFP_KERNEL); if (e) return &e->h; else return NULL;}/* * ID -> Name cache */static struct cache_head *idtoname_table[ENT_HASHMAX];static uint32_tidtoname_hash(struct ent *ent){ uint32_t hash; hash = hash_str(ent->authname, ENT_HASHBITS); hash = hash_long(hash ^ ent->id, ENT_HASHBITS); /* Flip LSB for user/group */ if (ent->type == IDMAP_TYPE_GROUP) hash ^= 1; return hash;}static voididtoname_request(struct cache_detail *cd, struct cache_head *ch, char **bpp, int *blen){ struct ent *ent = container_of(ch, struct ent, h); char idstr[11]; qword_add(bpp, blen, ent->authname); snprintf(idstr, sizeof(idstr), "%u", ent->id); qword_add(bpp, blen, ent->type == IDMAP_TYPE_GROUP ? "group" : "user"); qword_add(bpp, blen, idstr); (*bpp)[-1] = '\n';}static intidtoname_match(struct cache_head *ca, struct cache_head *cb){ struct ent *a = container_of(ca, struct ent, h); struct ent *b = container_of(cb, struct ent, h); return (a->id == b->id && a->type == b->type && strcmp(a->authname, b->authname) == 0);}static intidtoname_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h){ struct ent *ent; if (h == NULL) { seq_puts(m, "#domain type id [name]\n"); return 0; } ent = container_of(h, struct ent, h); seq_printf(m, "%s %s %u", ent->authname, ent->type == IDMAP_TYPE_GROUP ? "group" : "user", ent->id); if (test_bit(CACHE_VALID, &h->flags)) seq_printf(m, " %s", ent->name); seq_printf(m, "\n"); return 0;}static voidwarn_no_idmapd(struct cache_detail *detail){ printk("nfsd: nfsv4 idmapping failing: has idmapd %s?\n", detail->last_close? "died" : "not been started");}static int idtoname_parse(struct cache_detail *, char *, int);static struct ent *idtoname_lookup(struct ent *);static struct ent *idtoname_update(struct ent *, struct ent *);static struct cache_detail idtoname_cache = { .owner = THIS_MODULE, .hash_size = ENT_HASHMAX, .hash_table = idtoname_table, .name = "nfs4.idtoname", .cache_put = ent_put, .cache_request = idtoname_request, .cache_parse = idtoname_parse, .cache_show = idtoname_show, .warn_no_listener = warn_no_idmapd, .match = idtoname_match, .init = ent_init, .update = ent_init, .alloc = ent_alloc,};intidtoname_parse(struct cache_detail *cd, char *buf, int buflen){ struct ent ent, *res; char *buf1, *bp; int len; int error = -EINVAL; if (buf[buflen - 1] != '\n') return (-EINVAL); buf[buflen - 1]= '\0'; buf1 = kmalloc(PAGE_SIZE, GFP_KERNEL); if (buf1 == NULL) return (-ENOMEM); memset(&ent, 0, sizeof(ent)); /* Authentication name */ if (qword_get(&buf, buf1, PAGE_SIZE) <= 0) goto out; memcpy(ent.authname, buf1, sizeof(ent.authname)); /* Type */ if (qword_get(&buf, buf1, PAGE_SIZE) <= 0) goto out; ent.type = strcmp(buf1, "user") == 0 ? IDMAP_TYPE_USER : IDMAP_TYPE_GROUP; /* ID */ if (qword_get(&buf, buf1, PAGE_SIZE) <= 0) goto out; ent.id = simple_strtoul(buf1, &bp, 10); if (bp == buf1) goto out; /* expiry */ ent.h.expiry_time = get_expiry(&buf); if (ent.h.expiry_time == 0) goto out; error = -ENOMEM; res = idtoname_lookup(&ent); if (!res) goto out; /* Name */ error = -EINVAL; len = qword_get(&buf, buf1, PAGE_SIZE); if (len < 0) goto out; if (len == 0) set_bit(CACHE_NEGATIVE, &ent.h.flags); else { if (error >= IDMAP_NAMESZ) { error = -EINVAL; goto out; } memcpy(ent.name, buf1, sizeof(ent.name)); } error = -ENOMEM; res = idtoname_update(&ent, res); if (res == NULL) goto out; cache_put(&res->h, &idtoname_cache); error = 0;out: kfree(buf1); return error;}static struct ent *idtoname_lookup(struct ent *item){ struct cache_head *ch = sunrpc_cache_lookup(&idtoname_cache, &item->h, idtoname_hash(item)); if (ch) return container_of(ch, struct ent, h); else return NULL;}static struct ent *idtoname_update(struct ent *new, struct ent *old){ struct cache_head *ch = sunrpc_cache_update(&idtoname_cache, &new->h, &old->h, idtoname_hash(new)); if (ch) return container_of(ch, struct ent, h); else return NULL;}/* * Name -> ID cache */static struct cache_head *nametoid_table[ENT_HASHMAX];static inline intnametoid_hash(struct ent *ent){ return hash_str(ent->name, ENT_HASHBITS);}static voidnametoid_request(struct cache_detail *cd, struct cache_head *ch, char **bpp, int *blen){ struct ent *ent = container_of(ch, struct ent, h); qword_add(bpp, blen, ent->authname); qword_add(bpp, blen, ent->type == IDMAP_TYPE_GROUP ? "group" : "user"); qword_add(bpp, blen, ent->name); (*bpp)[-1] = '\n';}static intnametoid_match(struct cache_head *ca, struct cache_head *cb){ struct ent *a = container_of(ca, struct ent, h); struct ent *b = container_of(cb, struct ent, h); return (a->type == b->type && strcmp(a->name, b->name) == 0 &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -