From: NeilBrown Updated version which uses ascii-encoding of messages, from http://www.citi.umich.edu/u/marius/linux-2.5.70-idmap-server-new.diff as of October 14, 2003. --- fs/nfsd/Makefile | 2 fs/nfsd/nfs4idmap.c | 569 ++++++++++++++++++++++++++++++++++ fs/nfsd/nfs4proc.c | 3 fs/nfsd/nfs4xdr.c | 54 +-- fs/nfsd/nfsctl.c | 7 fs/nfsd/nfsproc.c | 1 include/linux/nfsd/xdr4.h | 6 include/linux/nfsd_idmap.h | 54 +++ net/sunrpc/auth_gss/gss_mech_switch.c | 1 9 files changed, 668 insertions(+), 29 deletions(-) diff -puN fs/nfsd/Makefile~knfsd-IDmap-support fs/nfsd/Makefile --- 25/fs/nfsd/Makefile~knfsd-IDmap-support 2004-02-25 02:32:04.000000000 -0800 +++ 25-akpm/fs/nfsd/Makefile 2004-02-25 02:32:04.000000000 -0800 @@ -7,5 +7,5 @@ obj-$(CONFIG_NFSD) += nfsd.o nfsd-y := nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \ export.o auth.o lockd.o nfscache.o nfsxdr.o stats.o nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o -nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o +nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o nfsd-objs := $(nfsd-y) diff -puN /dev/null fs/nfsd/nfs4idmap.c --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25-akpm/fs/nfsd/nfs4idmap.c 2004-02-25 02:32:04.000000000 -0800 @@ -0,0 +1,569 @@ +/* + * 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 + * + * 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 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 1 + +struct ent { + struct cache_head h; + int type; /* User / Group */ + uid_t id; + char name[IDMAP_NAMESZ]; + char authname[IDMAP_NAMESZ]; +}; + +#define DefineSimpleCacheLookupMap(STRUCT, FUNC) \ + DefineCacheLookup(struct STRUCT, h, FUNC##_lookup, \ + (struct STRUCT *item, int set), /*no setup */, \ + & FUNC##_cache, FUNC##_hash(item), FUNC##_match(item, tmp), \ + STRUCT##_init(new, item), STRUCT##_update(tmp, item), 0) + +/* Common entry handling */ + +#define ENT_HASHBITS 8 +#define ENT_HASHMAX (1 << ENT_HASHBITS) +#define ENT_HASHMASK (ENT_HASHMAX - 1) + +static inline void +ent_init(struct ent *new, struct ent *itm) +{ + 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 inline void +ent_update(struct ent *new, struct ent *itm) +{ + ent_init(new, itm); +} + +void +ent_put(struct cache_head *ch, struct cache_detail *cd) +{ + if (cache_put(ch, cd)) { + struct ent *map = container_of(ch, struct ent, h); + kfree(map); + } +} + +/* + * ID -> Name cache + */ + +static struct cache_head *idtoname_table[ENT_HASHMAX]; + +static uint32_t +idtoname_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 void +idtoname_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), "%d", ent->id); + qword_add(bpp, blen, ent->type == IDMAP_TYPE_GROUP ? "group" : "user"); + qword_add(bpp, blen, idstr); + + (*bpp)[-1] = '\n'; +} + +static inline int +idtoname_match(struct ent *a, struct ent *b) +{ + return (a->id == b->id && a->type == b->type && + strcmp(a->authname, b->authname) == 0); +} + +static int +idtoname_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 %d", 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 int idtoname_parse(struct cache_detail *, char *, int); +static struct ent *idtoname_lookup(struct ent *, int); + +struct cache_detail idtoname_cache = { + .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, +}; + +int +idtoname_parse(struct cache_detail *cd, char *buf, int buflen) +{ + struct ent ent, *res; + char *buf1, *bp; + 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; + + /* Name */ + error = qword_get(&buf, buf1, PAGE_SIZE); + if (error == -EINVAL) + goto out; + if (error == -ENOENT) + 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; + if ((res = idtoname_lookup(&ent, 1)) == NULL) + goto out; + + ent_put(&res->h, &idtoname_cache); + + error = 0; +out: + kfree(buf1); + + return error; +} + +static DefineSimpleCacheLookupMap(ent, idtoname); + +/* + * Name -> ID cache + */ + +static struct cache_head *nametoid_table[ENT_HASHMAX]; + +static inline int +nametoid_hash(struct ent *ent) +{ + return hash_str(ent->name, ENT_HASHBITS); +} + +void +nametoid_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 inline int +nametoid_match(struct ent *a, struct ent *b) +{ + return (a->type == b->type && strcmp(a->name, b->name) == 0 && + strcmp(a->authname, b->authname) == 0); +} + +static int +nametoid_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h) +{ + struct ent *ent; + + if (h == NULL) { + seq_puts(m, "#domain type name [id]\n"); + return 0; + } + ent = container_of(h, struct ent, h); + seq_printf(m, "%s %s %s", ent->authname, + ent->type == IDMAP_TYPE_GROUP ? "group" : "user", + ent->name); + if (test_bit(CACHE_VALID, &h->flags)) + seq_printf(m, " %d", ent->id); + seq_printf(m, "\n"); + return 0; +} + +static struct ent *nametoid_lookup(struct ent *, int); +int nametoid_parse(struct cache_detail *, char *, int); + +struct cache_detail nametoid_cache = { + .hash_size = ENT_HASHMAX, + .hash_table = nametoid_table, + .name = "nfs4.nametoid", + .cache_put = ent_put, + .cache_request = nametoid_request, + .cache_parse = nametoid_parse, + .cache_show = nametoid_show, +}; + +int +nametoid_parse(struct cache_detail *cd, char *buf, int buflen) +{ + struct ent ent, *res; + char *buf1; + 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; + + /* Name */ + error = qword_get(&buf, buf1, PAGE_SIZE); + if (error <= 0 || error >= IDMAP_NAMESZ) + goto out; + memcpy(ent.name, buf1, sizeof(ent.name)); + + /* expiry */ + ent.h.expiry_time = get_expiry(&buf); + if (ent.h.expiry_time == 0) + goto out; + + /* ID */ + error = get_int(&buf, &ent.id); + if (error == -EINVAL) + goto out; + if (error == -ENOENT) + set_bit(CACHE_NEGATIVE, &ent.h.flags); + + error = -ENOMEM; + if ((res = nametoid_lookup(&ent, 1)) == NULL) + goto out; + + ent_put(&res->h, &nametoid_cache); + error = 0; +out: + kfree(buf1); + + return (error); +} + +static DefineSimpleCacheLookupMap(ent, nametoid); + +/* + * Exported API + */ + +void +nfsd_idmap_init(void) +{ + cache_register(&idtoname_cache); + cache_register(&nametoid_cache); +} + +void +nfsd_idmap_shutdown(void) +{ + cache_unregister(&idtoname_cache); + cache_unregister(&nametoid_cache); +} + +/* + * Deferred request handling + */ + +struct idmap_defer_req { + struct cache_req req; + struct cache_deferred_req deferred_req; + wait_queue_head_t waitq; + atomic_t count; +}; + +static void +put_mdr(struct idmap_defer_req *mdr) +{ + if (atomic_dec_and_test(&mdr->count)) + kfree(mdr); +} + +static void +idmap_revisit(struct cache_deferred_req *dreq, int toomany) +{ + struct idmap_defer_req *mdr = + container_of(dreq, struct idmap_defer_req, deferred_req); + + wake_up(&mdr->waitq); + put_mdr(mdr); +} + +static struct cache_deferred_req * +idmap_defer(struct cache_req *req) +{ + struct idmap_defer_req *mdr = + container_of(req, struct idmap_defer_req, req); + + mdr->deferred_req.revisit = idmap_revisit; + return (&mdr->deferred_req); +} + +static int threads_waiting = 0; + +static inline int +idmap_lookup_wait(struct idmap_defer_req *mdr, wait_queue_t waitq, struct + svc_rqst *rqstp) { + int ret = -ETIMEDOUT; + + set_task_state(current, TASK_INTERRUPTIBLE); + lock_kernel(); + /* XXX: Does it matter that threads_waiting isn't per-server? */ + /* Note: BKL prevents races with nfsd_svc and other lookups */ + if (2 * threads_waiting > rqstp->rq_server->sv_nrthreads) + goto out; + threads_waiting++; + schedule_timeout(10 * HZ); + threads_waiting--; + ret = 0; +out: + unlock_kernel(); + remove_wait_queue(&mdr->waitq, &waitq); + set_task_state(current, TASK_RUNNING); + put_mdr(mdr); + return ret; +} + +static int +idmap_lookup(struct svc_rqst *rqstp, + struct ent *(*lookup_fn)(struct ent *, int), struct ent *key, + struct cache_detail *detail, struct ent **item) +{ + struct idmap_defer_req *mdr; + DECLARE_WAITQUEUE(waitq, current); + int ret; + + *item = lookup_fn(key, 0); + if (!*item) + return -ENOMEM; + mdr = kmalloc(sizeof(*mdr), GFP_KERNEL); + memset(mdr, 0, sizeof(*mdr)); + init_waitqueue_head(&mdr->waitq); + add_wait_queue(&mdr->waitq, &waitq); + atomic_set(&mdr->count, 2); + mdr->req.defer = idmap_defer; + ret = cache_check(detail, &(*item)->h, &mdr->req); + if (ret == -EAGAIN) { + ret = idmap_lookup_wait(mdr, waitq, rqstp); + if (ret) + goto out; + /* Try again, but don't wait. */ + *item = lookup_fn(key, 0); + ret = -ENOMEM; + if (!*item) + goto out; + ret = -ETIMEDOUT; + if (!test_bit(CACHE_VALID, &(*item)->h.flags)) { + ent_put(&(*item)->h, detail); + goto out; + } + ret = cache_check(detail, &(*item)->h, NULL); + } +out: + return ret; +} + +static int +idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, + uid_t *id) +{ + struct ent *item, key = { + .type = type, + }; + int ret; + + if (namelen + 1 > sizeof(key.name)) + return -EINVAL; + memcpy(key.name, name, namelen); + key.name[namelen] = '\0'; + strlcpy(key.authname, rqstp->rq_client->name, sizeof(key.authname)); + ret = idmap_lookup(rqstp, nametoid_lookup, &key, &nametoid_cache, &item); + if (ret) + return ret; + *id = item->id; + ent_put(&item->h, &nametoid_cache); + return 0; +} + +static int +idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name) +{ + struct ent *item, key = { + .id = id, + .type = type, + }; + int ret; + + strlcpy(key.authname, rqstp->rq_client->name, sizeof(key.authname)); + ret = idmap_lookup(rqstp, idtoname_lookup, &key, &idtoname_cache, &item); + if (ret) + return ret; + ret = strlen(item->name); + BUG_ON(ret > IDMAP_NAMESZ); + memcpy(name, item->name, ret); + ent_put(&item->h, &idtoname_cache); + return ret; +} + +int +nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen, + __u32 *id) +{ + return idmap_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen, id); +} + +int +nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen, + __u32 *id) +{ + return idmap_name_to_id(rqstp, IDMAP_TYPE_GROUP, name, namelen, id); +} + +int +nfsd_map_uid_to_name(struct svc_rqst *rqstp, __u32 id, char *name) +{ + return idmap_id_to_name(rqstp, IDMAP_TYPE_USER, id, name); +} + +int +nfsd_map_gid_to_name(struct svc_rqst *rqstp, __u32 id, char *name) +{ + return idmap_id_to_name(rqstp, IDMAP_TYPE_GROUP, id, name); +} diff -puN fs/nfsd/nfs4proc.c~knfsd-IDmap-support fs/nfsd/nfs4proc.c --- 25/fs/nfsd/nfs4proc.c~knfsd-IDmap-support 2004-02-25 02:32:04.000000000 -0800 +++ 25-akpm/fs/nfsd/nfs4proc.c 2004-02-25 02:32:04.000000000 -0800 @@ -568,7 +568,8 @@ nfsd4_verify(struct svc_rqst *rqstp, str status = nfsd4_encode_fattr(current_fh, current_fh->fh_export, current_fh->fh_dentry, buf, - &count, verify->ve_bmval); + &count, verify->ve_bmval, + rqstp); /* this means that nfsd4_encode_fattr() ran out of space */ if (status == nfserr_resource && count == 0) diff -puN fs/nfsd/nfs4xdr.c~knfsd-IDmap-support fs/nfsd/nfs4xdr.c --- 25/fs/nfsd/nfs4xdr.c~knfsd-IDmap-support 2004-02-25 02:32:04.000000000 -0800 +++ 25-akpm/fs/nfsd/nfs4xdr.c 2004-02-25 02:32:04.000000000 -0800 @@ -51,10 +51,10 @@ #include #include #include -#include #include #include #include +#include #define NFSDDBG_FACILITY NFSDDBG_XDR @@ -373,7 +373,7 @@ nfsd4_decode_fattr(struct nfsd4_compound READMEM(buf, dummy32); if (check_utf8(buf, dummy32)) return nfserr_inval; - if ((status = name_get_uid(buf, dummy32, &iattr->ia_uid))) + if ((status = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid))) goto out_nfserr; iattr->ia_valid |= ATTR_UID; } @@ -386,7 +386,7 @@ nfsd4_decode_fattr(struct nfsd4_compound READMEM(buf, dummy32); if (check_utf8(buf, dummy32)) return nfserr_inval; - if ((status = name_get_gid(buf, dummy32, &iattr->ia_gid))) + if ((status = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid))) goto out_nfserr; iattr->ia_valid |= ATTR_GID; } @@ -1239,13 +1239,16 @@ static u32 nfs4_ftypes[16] = { */ int nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, - struct dentry *dentry, u32 *buffer, int *countp, u32 *bmval) + struct dentry *dentry, u32 *buffer, int *countp, u32 *bmval, + struct svc_rqst *rqstp) { u32 bmval0 = bmval[0]; u32 bmval1 = bmval[1]; struct kstat stat; - struct name_ent *owner = NULL; - struct name_ent *group = NULL; + char owner[IDMAP_NAMESZ]; + u32 ownerlen = 0; + char group[IDMAP_NAMESZ]; + u32 grouplen = 0; struct svc_fh tempfh; struct kstatfs statfs; int buflen = *countp << 2; @@ -1277,14 +1280,20 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s fhp = &tempfh; } if (bmval1 & FATTR4_WORD1_OWNER) { - status = name_get_user(stat.uid, &owner); - if (status) + int temp = nfsd_map_uid_to_name(rqstp, stat.uid, owner); + if (temp < 0) { + status = temp; goto out_nfserr; + } + ownerlen = (unsigned) temp; } if (bmval1 & FATTR4_WORD1_OWNER_GROUP) { - status = name_get_group(stat.gid, &group); - if (status) + int temp = nfsd_map_gid_to_name(rqstp, stat.gid, group); + if (temp < 0) { + status = temp; goto out_nfserr; + } + grouplen = (unsigned) temp; } if ((buflen -= 16) < 0) @@ -1485,20 +1494,18 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s WRITE32(stat.nlink); } if (bmval1 & FATTR4_WORD1_OWNER) { - int namelen = strlen(owner->name); - buflen -= (XDR_QUADLEN(namelen) << 2) + 4; + buflen -= (XDR_QUADLEN(ownerlen) << 2) + 4; if (buflen < 0) goto out_resource; - WRITE32(namelen); - WRITEMEM(owner->name, namelen); + WRITE32(ownerlen); + WRITEMEM(owner, ownerlen); } if (bmval1 & FATTR4_WORD1_OWNER_GROUP) { - int namelen = strlen(group->name); - buflen -= (XDR_QUADLEN(namelen) << 2) + 4; + buflen -= (XDR_QUADLEN(grouplen) << 2) + 4; if (buflen < 0) goto out_resource; - WRITE32(namelen); - WRITEMEM(group->name, namelen); + WRITE32(grouplen); + WRITEMEM(group, grouplen); } if (bmval1 & FATTR4_WORD1_RAWDEV) { if ((buflen -= 8) < 0) @@ -1566,10 +1573,6 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s out: if (fhp == &tempfh) fh_put(&tempfh); - if (owner) - name_put(owner); - if (group) - name_put(group); return status; out_nfserr: status = nfserrno(status); @@ -1648,7 +1651,8 @@ nfsd4_encode_dirent(struct readdir_cd *c } nfserr = nfsd4_encode_fattr(NULL, exp, - dentry, p, &buflen, cd->rd_bmval); + dentry, p, &buflen, cd->rd_bmval, + cd->rd_rqstp); if (!nfserr) { p += buflen; goto out; @@ -1771,7 +1775,8 @@ nfsd4_encode_getattr(struct nfsd4_compou buflen = resp->end - resp->p - (COMPOUND_ERR_SLACK_SPACE >> 2); nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry, - resp->p, &buflen, getattr->ga_bmval); + resp->p, &buflen, getattr->ga_bmval, + resp->rqstp); if (!nfserr) resp->p += buflen; @@ -2381,6 +2386,7 @@ nfs4svc_decode_compoundargs(struct svc_r args->tmpp = NULL; args->to_free = NULL; args->ops = args->iops; + args->rqstp = rqstp; status = nfsd4_decode_compound(args); if (status) { diff -puN fs/nfsd/nfsctl.c~knfsd-IDmap-support fs/nfsd/nfsctl.c --- 25/fs/nfsd/nfsctl.c~knfsd-IDmap-support 2004-02-25 02:32:04.000000000 -0800 +++ 25-akpm/fs/nfsd/nfsctl.c 2004-02-25 02:32:04.000000000 -0800 @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -437,6 +438,9 @@ static int __init init_nfsd(void) nfsd_cache_init(); /* RPC reply cache */ nfsd_export_init(); /* Exports table */ nfsd_lockd_init(); /* lockd->nfsd callbacks */ +#ifdef CONFIG_NFSD_V4 + nfsd_idmap_init(); /* Name to ID mapping */ +#endif /* CONFIG_NFSD_V4 */ if (proc_mkdir("fs/nfs", 0)) { struct proc_dir_entry *entry; entry = create_proc_entry("fs/nfs/exports", 0, NULL); @@ -463,6 +467,9 @@ static void __exit exit_nfsd(void) remove_proc_entry("fs/nfs", NULL); nfsd_stat_shutdown(); nfsd_lockd_shutdown(); +#ifdef CONFIG_NFSD_V4 + nfsd_idmap_shutdown(); +#endif /* CONFIG_NFSD_V4 */ unregister_filesystem(&nfsd_fs_type); } diff -puN fs/nfsd/nfsproc.c~knfsd-IDmap-support fs/nfsd/nfsproc.c --- 25/fs/nfsd/nfsproc.c~knfsd-IDmap-support 2004-02-25 02:32:04.000000000 -0800 +++ 25-akpm/fs/nfsd/nfsproc.c 2004-02-25 02:32:04.000000000 -0800 @@ -585,6 +585,7 @@ nfserrno (int errno) { nfserr_dquot, -EDQUOT }, #endif { nfserr_stale, -ESTALE }, + { nfserr_jukebox, -ETIMEDOUT }, { nfserr_dropit, -EAGAIN }, { nfserr_dropit, -ENOMEM }, { -1, -EIO } diff -puN /dev/null include/linux/nfsd_idmap.h --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25-akpm/include/linux/nfsd_idmap.h 2004-02-25 02:32:04.000000000 -0800 @@ -0,0 +1,54 @@ +/* + * include/linux/nfsd_idmap.h + * + * Mapping of UID to name and vice versa. + * + * Copyright (c) 2002, 2003 The Regents of the University of + * Michigan. All rights reserved. +> * + * Marius Aamodt Eriksen + * + * 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. + */ + +#ifndef LINUX_NFSD_IDMAP_H +#define LINUX_NFSD_IDMAP_H + +#include +#include + +/* XXX from linux/nfs_idmap.h */ +#define IDMAP_NAMESZ 128 + +void nfsd_idmap_init(void); +void nfsd_idmap_shutdown(void); + +int nfsd_map_name_to_uid(struct svc_rqst *, const char *, size_t, __u32 *); +int nfsd_map_name_to_gid(struct svc_rqst *, const char *, size_t, __u32 *); +int nfsd_map_uid_to_name(struct svc_rqst *, __u32, char *); +int nfsd_map_gid_to_name(struct svc_rqst *, __u32, char *); + +#endif /* LINUX_NFSD_IDMAP_H */ diff -puN include/linux/nfsd/xdr4.h~knfsd-IDmap-support include/linux/nfsd/xdr4.h --- 25/include/linux/nfsd/xdr4.h~knfsd-IDmap-support 2004-02-25 02:32:04.000000000 -0800 +++ 25-akpm/include/linux/nfsd/xdr4.h 2004-02-25 02:32:04.000000000 -0800 @@ -375,7 +375,9 @@ struct nfsd4_compoundargs { struct tmpbuf *next; void *buf; } *to_free; - + + struct svc_rqst *rqstp; + u32 taglen; char * tag; u32 minorversion; @@ -419,7 +421,7 @@ void nfsd4_encode_operation(struct nfsd4 void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op); int nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, u32 *buffer, int *countp, - u32 *bmval); + u32 *bmval, struct svc_rqst *); extern int nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid); extern int nfsd4_setclientid_confirm(struct svc_rqst *rqstp, diff -puN net/sunrpc/auth_gss/gss_mech_switch.c~knfsd-IDmap-support net/sunrpc/auth_gss/gss_mech_switch.c --- 25/net/sunrpc/auth_gss/gss_mech_switch.c~knfsd-IDmap-support 2004-02-25 02:32:04.000000000 -0800 +++ 25-akpm/net/sunrpc/auth_gss/gss_mech_switch.c 2004-02-25 02:32:04.000000000 -0800 @@ -43,7 +43,6 @@ #include #include #include -#include #ifdef RPC_DEBUG # define RPCDBG_FACILITY RPCDBG_AUTH _