aboutsummaryrefslogtreecommitdiff
path: root/nfsd/cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'nfsd/cache.c')
-rw-r--r--nfsd/cache.c381
1 files changed, 229 insertions, 152 deletions
diff --git a/nfsd/cache.c b/nfsd/cache.c
index 745a7c8e..7b96dbc2 100644
--- a/nfsd/cache.c
+++ b/nfsd/cache.c
@@ -1,5 +1,5 @@
-/*
- Copyright (C) 1996 Free Software Foundation, Inc.
+/* cache.c - Cache operations for the nfs daemon.
+ Copyright (C) 1996,98,99,2000,02 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -20,9 +20,12 @@
#include <string.h>
+#include <sys/mman.h>
#include <hurd/fsys.h>
#include <assert.h>
#include <string.h>
+#include <hurd/io.h>
+#include <hurd/auth.h>
#include "nfsd.h"
@@ -31,7 +34,6 @@
#define malloc spoogie_woogie /* ugh^2. */
#include <rpc/types.h>
#include <rpc/auth.h>
-#include <rpc/auth_unix.h>
#undef malloc
#define IDHASH_TABLE_SIZE 1024
@@ -44,9 +46,9 @@ spin_lock_t idhashlock = SPIN_LOCK_INITIALIZER;
static int nfreeids;
static int leastidlastuse;
-/* Compare I against the specified set of users/groups. */
+/* Compare I against the specified set of users/groups. */
/* Use of int in decl of UIDS and GIDS is correct here; that's
- the NFS type because they come in in known 32 bit slots. */
+ the NFS type because they come in in known 32 bit slots. */
static int
idspec_compare (struct idspec *i, int nuids, int ngids,
int *uids, int *gids)
@@ -56,20 +58,20 @@ idspec_compare (struct idspec *i, int nuids, int ngids,
return 0;
assert (sizeof (int) == sizeof (uid_t));
-
+
if (bcmp (i->uids, uids, nuids * sizeof (uid_t))
|| bcmp (i->gids, gids, ngids * sizeof (gid_t)))
return 0;
-
+
return 1;
}
-/* Compute a hash value for a given user spec */
+/* Compute a hash value for a given user spec. */
static int
idspec_hash (int nuids, int ngids, int *uids, int *gids)
{
int hash, n;
-
+
hash = nuids + ngids;
for (n = 0; n < ngids; n++)
hash += gids[n];
@@ -79,7 +81,7 @@ idspec_hash (int nuids, int ngids, int *uids, int *gids)
return hash;
}
-/* Lookup a user spec in the hash table and allocate a reference */
+/* Lookup a user spec in the hash table and allocate a reference. */
static struct idspec *
idspec_lookup (int nuids, int ngids, int *uids, int *gids)
{
@@ -98,15 +100,15 @@ idspec_lookup (int nuids, int ngids, int *uids, int *gids)
spin_unlock (&idhashlock);
return i;
}
-
+
assert (sizeof (uid_t) == sizeof (int));
i = malloc (sizeof (struct idspec));
i->nuids = nuids;
i->ngids = ngids;
i->uids = malloc (nuids * sizeof (uid_t));
i->gids = malloc (ngids * sizeof (gid_t));
- bcopy (uids, i->uids, nuids * sizeof (uid_t));
- bcopy (gids, i->gids, ngids * sizeof (gid_t));
+ memcpy (i->uids, uids, nuids * sizeof (uid_t));
+ memcpy (i->gids, gids, ngids * sizeof (gid_t));
i->references = 1;
i->next = idhashtable[hash];
@@ -129,42 +131,53 @@ process_cred (int *p, struct idspec **credp)
int ngids;
int firstgid;
int i;
-
- type = ntohl (*p++);
+
+ type = ntohl (*p);
+ p++;
if (type != AUTH_UNIX)
{
- int size = ntohl (*p++);
+ int size = ntohl (*p);
+ p++;
*credp = idspec_lookup (0, 0, 0, 0);
- return p + INTSIZE (size);
+ p += INTSIZE (size);
+ }
+ else
+ {
+ p++; /* Skip size. */
+ p++; /* Skip seconds. */
+ len = ntohl (*p);
+ p++;
+ p += INTSIZE (len); /* Skip hostname. */
+
+ uid = p++; /* Remember location of uid. */
+ *uid = ntohl (*uid);
+
+ firstgid = *(p++); /* Remember first gid. */
+ gids = p; /* Here is where the array will start. */
+ ngids = ntohl (*p);
+ p++;
+
+ /* Now swap the first gid to be the first element of the
+ array. */
+ *gids = firstgid;
+ ngids++; /* And count it. */
+
+ /* And byteswap the gids. */
+ for (i = 0; i < ngids; i++)
+ gids[i] = ntohl (gids[i]);
+
+ p += ngids - 1;
+
+ *credp = idspec_lookup (1, ngids, uid, gids);
}
-
- p++; /* skip size */
- p++; /* skip seconds */
- len = ntohl (*p++);
- p += INTSIZE (len); /* skip hostname */
-
- uid = p++; /* remember loc of uid */
- *uid = ntohl (*uid);
-
- firstgid = *p++; /* remember first gid */
- gids = p; /* here's where the array will start */
- ngids = ntohl (*p++);
-
- /* Now swap the first gid to be the first element of the array */
- *gids = firstgid;
- ngids++; /* and count it */
-
- /* And byteswap the gids */
- for (i = 1; i < ngids; i++)
- gids[i] = ntohl (gids[i]);
-
- /* Next is the verf field; skip it entirely */
- p++; /* skip id */
- len = htonl (*p++);
+
+ /* Next is the verf field; skip it entirely. */
+ p++; /* Skip ID. */
+ len = htonl (*p);
+ p++;
p += INTSIZE (len);
-
- *credp = idspec_lookup (1, ngids, uid, gids);
+
return p;
}
@@ -195,32 +208,43 @@ cred_ref (struct idspec *i)
void
scan_creds ()
{
- struct idspec *i;
int n;
int newleast = mapped_time->seconds;
spin_lock (&idhashlock);
+
if (mapped_time->seconds - leastidlastuse > ID_KEEP_TIMEOUT)
- for (n = 0; n < IDHASH_TABLE_SIZE && nfreeids; n++)
- for (i = idhashtable[n]; i && nfreeids; i = i->next)
- if (!i->references
- && mapped_time->seconds - i->lastuse > ID_KEEP_TIMEOUT)
- {
- nfreeids--;
- *i->prevp = i->next;
- if (i->next)
- i->next->prevp = i->prevp;
- free (i->uids);
- free (i->gids);
- free (i);
- }
- else
- if (!i->references && newleast > i->lastuse)
- newleast = i->lastuse;
-
- /* If we didn't bail early, then this is valid */
- if (nfreeids)
- leastidlastuse = newleast;
+ {
+ for (n = 0; n < IDHASH_TABLE_SIZE && nfreeids; n++)
+ {
+ struct idspec *i = idhashtable[n];
+
+ while (i && nfreeids)
+ {
+ struct idspec *next_i = i->next;
+
+ if (!i->references
+ && mapped_time->seconds - i->lastuse > ID_KEEP_TIMEOUT)
+ {
+ nfreeids--;
+ *i->prevp = i->next;
+ if (i->next)
+ i->next->prevp = i->prevp;
+ free (i->uids);
+ free (i->gids);
+ free (i);
+ }
+ else if (!i->references && newleast > i->lastuse)
+ newleast = i->lastuse;
+
+ i = next_i;
+ }
+ }
+
+ /* If we didn't bail early, then this is valid. */
+ if (nfreeids)
+ leastidlastuse = newleast;
+ }
spin_unlock (&idhashlock);
}
@@ -235,11 +259,11 @@ static int
fh_hash (char *fhandle, struct idspec *i)
{
int hash = 0, n;
-
- for (n = 0; n < NFS_FHSIZE; n++)
+
+ for (n = 0; n < NFS2_FHSIZE; n++)
hash += fhandle[n];
- hash += (int) i >> 6;
- return hash;
+ hash += (intptr_t) i >> 6;
+ return hash % FHHASH_TABLE_SIZE;
}
int *
@@ -249,35 +273,35 @@ lookup_cache_handle (int *p, struct cache_handle **cp, struct idspec *i)
struct cache_handle *c;
fsys_t fsys;
file_t port;
-
+
hash = fh_hash ((char *)p, i);
mutex_lock (&fhhashlock);
for (c = fhhashtable[hash]; c; c = c->next)
- if (c->ids == i && ! bcmp (c->handle, p, NFS_FHSIZE))
+ if (c->ids == i && ! bcmp (c->handle, p, NFS2_FHSIZE))
{
if (c->references == 0)
nfreefh--;
c->references++;
mutex_unlock (&fhhashlock);
*cp = c;
- return p + NFS_FHSIZE / sizeof (int);
+ return p + NFS2_FHSIZE / sizeof (int);
}
-
- /* Not found */
-
- /* First four bytes are our internal table of filesystems */
+
+ /* Not found. */
+
+ /* First four bytes are our internal table of filesystems. */
fsys = lookup_filesystem (*p);
if (fsys == MACH_PORT_NULL
|| fsys_getfile (fsys, i->uids, i->nuids, i->gids, i->ngids,
- (char *)(p + 1), NFS_FHSIZE - sizeof (int), &port))
+ (char *)(p + 1), NFS2_FHSIZE - sizeof (int), &port))
{
mutex_unlock (&fhhashlock);
*cp = 0;
- return p + NFS_FHSIZE / sizeof (int);
+ return p + NFS2_FHSIZE / sizeof (int);
}
-
+
c = malloc (sizeof (struct cache_handle));
- bcopy (p, c->handle, NFS_FHSIZE);
+ memcpy (c->handle, p, NFS2_FHSIZE);
cred_ref (i);
c->ids = i;
c->port = port;
@@ -288,10 +312,10 @@ lookup_cache_handle (int *p, struct cache_handle **cp, struct idspec *i)
c->next->prevp = &c->next;
c->prevp = &fhhashtable[hash];
fhhashtable[hash] = c;
-
+
mutex_unlock (&fhhashlock);
*cp = c;
- return p + NFS_FHSIZE / sizeof (int);
+ return p + NFS2_FHSIZE / sizeof (int);
}
void
@@ -309,91 +333,131 @@ cache_handle_rele (struct cache_handle *c)
mutex_unlock (&fhhashlock);
}
-void
+void
scan_fhs ()
{
- struct cache_handle *c;
int n;
int newleast = mapped_time->seconds;
-
+
mutex_lock (&fhhashlock);
+
if (mapped_time->seconds - leastfhlastuse > FH_KEEP_TIMEOUT)
- for (n = 0; n < FHHASH_TABLE_SIZE && nfreefh; n++)
- for (c = fhhashtable[n]; c && nfreefh; c = c->next)
- if (!c->references
- && mapped_time->seconds - c->lastuse > FH_KEEP_TIMEOUT)
- {
- nfreefh--;
- *c->prevp = c->next;
- if (c->next)
- c->next->prevp = c->prevp;
- cred_rele (c->ids);
- mach_port_deallocate (mach_task_self (), c->port);
- free (c);
- }
- else
- if (!c->references && newleast > c->lastuse)
- newleast = c->lastuse;
-
- /* If we didn't bail early, then this is valid. */
- if (nfreefh)
- leastfhlastuse = newleast;
+ {
+ for (n = 0; n < FHHASH_TABLE_SIZE && nfreefh; n++)
+ {
+ struct cache_handle *c = fhhashtable[n];
+
+ while (c && nfreefh)
+ {
+ struct cache_handle *next_c = c->next;
+
+ if (!c->references
+ && mapped_time->seconds - c->lastuse > FH_KEEP_TIMEOUT)
+ {
+ nfreefh--;
+ *c->prevp = c->next;
+ if (c->next)
+ c->next->prevp = c->prevp;
+ cred_rele (c->ids);
+ mach_port_deallocate (mach_task_self (), c->port);
+ free (c);
+ }
+ else if (!c->references && newleast > c->lastuse)
+ newleast = c->lastuse;
+
+ c = next_c;
+ }
+ }
+
+ /* If we didn't bail early, then this is valid. */
+ if (nfreefh)
+ leastfhlastuse = newleast;
+ }
mutex_unlock (&fhhashlock);
}
struct cache_handle *
-create_cached_handle (int fs, struct cache_handle *credc, file_t newport)
+create_cached_handle (int fs, struct cache_handle *credc, file_t userport)
{
- char fhandle[NFS_FHSIZE];
+ char fhandle[NFS2_FHSIZE];
error_t err;
struct cache_handle *c;
int hash;
char *bp = fhandle + sizeof (int);
- size_t handlelen = NFS_FHSIZE - sizeof (int);
+ size_t handlelen = NFS2_FHSIZE - sizeof (int);
+ mach_port_t newport, ref;
+
+ /* Authenticate USERPORT so that we can call file_getfh on it. */
+ ref = mach_reply_port ();
+ /* MAKE_SEND is safe becaue we destroy REF ourselves. */
+ if (io_reauthenticate (userport, ref, MACH_MSG_TYPE_MAKE_SEND)
+ || auth_user_authenticate (authserver, ref, MACH_MSG_TYPE_MAKE_SEND,
+ &newport))
+ {
+ /* Reauthentication has failed, but maybe the filesystem will let
+ us call file_getfh anyway. */
+ newport = userport;
+ }
+ else
+ mach_port_deallocate (mach_task_self (), userport);
+ mach_port_destroy (mach_task_self (), ref);
+ /* Fetch the file handle. */
*(int *)fhandle = fs;
err = file_getfh (newport, &bp, &handlelen);
- if (err || handlelen != NFS_FHSIZE - sizeof (int))
- {
- mach_port_deallocate (mach_task_self (), newport);
- return 0;
- }
+ mach_port_deallocate (mach_task_self (), newport);
+ if (err || handlelen != NFS2_FHSIZE - sizeof (int))
+ return 0;
if (bp != fhandle + sizeof (int))
{
- bcopy (bp, fhandle + sizeof (int), NFS_FHSIZE - sizeof (int));
- vm_deallocate (mach_task_self (), (vm_address_t) bp, handlelen);
+ memcpy (fhandle + sizeof (int), bp, NFS2_FHSIZE - sizeof (int));
+ munmap (bp, handlelen);
}
-
+
+ /* Cache it. */
hash = fh_hash (fhandle, credc->ids);
mutex_lock (&fhhashlock);
for (c = fhhashtable[hash]; c; c = c->next)
- if (c->ids == credc->ids && ! bcmp (fhandle, c->handle, NFS_FHSIZE))
+ if (c->ids == credc->ids && ! bcmp (fhandle, c->handle, NFS2_FHSIZE))
{
- /* Return this one */
+ /* Return this one. */
if (c->references == 0)
nfreefh--;
c->references++;
mutex_unlock (&fhhashlock);
- mach_port_deallocate (mach_task_self (), newport);
return c;
}
-
- /* Create it anew */
+
+ /* Always call fsys_getfile so that we don't depend on the
+ particular open modes of the port passed in. */
+
+ err = fsys_getfile (lookup_filesystem (fs),
+ credc->ids->uids, credc->ids->nuids,
+ credc->ids->gids, credc->ids->ngids,
+ fhandle + sizeof (int), NFS2_FHSIZE - sizeof (int),
+ &newport);
+ if (err)
+ {
+ mutex_unlock (&fhhashlock);
+ return 0;
+ }
+
+ /* Create it anew. */
c = malloc (sizeof (struct cache_handle));
- bcopy (fhandle, c->handle, NFS_FHSIZE);
+ memcpy (c->handle, fhandle, NFS2_FHSIZE);
cred_ref (credc->ids);
c->ids = credc->ids;
c->port = newport;
c->references = 1;
-
- /* And add it to the hash table */
+
+ /* And add it to the hash table. */
c->next = fhhashtable[hash];
if (c->next)
c->next->prevp = &c->next;
c->prevp = &fhhashtable[hash];
fhhashtable[hash] = c;
mutex_unlock (&fhhashlock);
-
+
return c;
}
@@ -406,19 +470,19 @@ static int leastreplylastuse;
/* Check the list of cached replies to see if this is a replay of a
previous transaction; if so, return the cache record. Otherwise,
- create a new cache record. */
+ create a new cache record. */
struct cached_reply *
-check_cached_replies (int xid,
+check_cached_replies (int xid,
struct sockaddr_in *sender)
{
struct cached_reply *cr;
int hash;
- hash = xid % REPLYHASH_TABLE_SIZE;
-
+ hash = abs(xid % REPLYHASH_TABLE_SIZE);
+
spin_lock (&replycachelock);
for (cr = replyhashtable[hash]; cr; cr = cr->next)
- if (cr->xid == xid
+ if (cr->xid == xid
&& !bcmp (sender, &cr->source, sizeof (struct sockaddr_in)))
{
cr->references++;
@@ -432,9 +496,10 @@ check_cached_replies (int xid,
cr = malloc (sizeof (struct cached_reply));
mutex_init (&cr->lock);
mutex_lock (&cr->lock);
- bcopy (sender, &cr->source, sizeof (struct sockaddr_in));
+ memcpy (&cr->source, sender, sizeof (struct sockaddr_in));
cr->xid = xid;
cr->data = 0;
+ cr->references = 1;
cr->next = replyhashtable[hash];
if (replyhashtable[hash])
@@ -447,7 +512,7 @@ check_cached_replies (int xid,
}
/* A cached reply returned by check_cached_replies is now no longer
- needed by its caller. */
+ needed by its caller. */
void
release_cached_reply (struct cached_reply *cr)
{
@@ -467,30 +532,42 @@ release_cached_reply (struct cached_reply *cr)
void
scan_replies ()
{
- struct cached_reply *cr;
int n;
int newleast = mapped_time->seconds;
-
+
spin_lock (&replycachelock);
+
if (mapped_time->seconds - leastreplylastuse > REPLY_KEEP_TIMEOUT)
- for (n = 0; n < REPLYHASH_TABLE_SIZE && nfreereplies; n++)
- for (cr = replyhashtable[n]; cr && nfreereplies; cr = cr->next)
- if (!cr->references
- && mapped_time->seconds - cr->lastuse > REPLY_KEEP_TIMEOUT)
- {
- nfreereplies--;
- *cr->prevp = cr->next;
- if (cr->next)
- cr->next->prevp = cr->prevp;
- if (cr->data)
- free (cr->data);
- }
- else
- if (!cr->references && newleast > cr->lastuse)
- newleast = cr->lastuse;
-
- /* If we didn't bail early, then this is valid */
- if (nfreereplies)
- leastreplylastuse = newleast;
+ {
+ for (n = 0; n < REPLYHASH_TABLE_SIZE && nfreereplies; n++)
+ {
+ struct cached_reply *cr = replyhashtable[n];
+
+ while (cr && nfreereplies)
+ {
+ struct cached_reply *next_cr = cr->next;
+
+ if (!cr->references
+ && mapped_time->seconds - cr->lastuse > REPLY_KEEP_TIMEOUT)
+ {
+ nfreereplies--;
+ *cr->prevp = cr->next;
+ if (cr->next)
+ cr->next->prevp = cr->prevp;
+ if (cr->data)
+ free (cr->data);
+ free (cr);
+ }
+ else if (!cr->references && newleast > cr->lastuse)
+ newleast = cr->lastuse;
+
+ cr = next_cr;
+ }
+ }
+
+ /* If we didn't bail early, then this is valid. */
+ if (nfreereplies)
+ leastreplylastuse = newleast;
+ }
spin_unlock (&replycachelock);
}