nfs4_db.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/id_space.h>
#include <nfs/nfs4_db_impl.h>
static int rfs4_reap_interval = RFS4_REAP_INTERVAL;
static void rfs4_dbe_destroy(rfs4_dbe_t *);
static void rfs4_start_reaper(rfs4_table_t *);
{
return (e->id);
}
void
{
}
/*
* rfs4_dbe_rele_nolock only decrements the reference count of the entry.
*/
void
{
}
{
return (e->refcnt);
}
/*
* Mark an entry such that the dbsearch will skip it.
* Caller does not want this entry to be found any longer
*/
void
{
e->skipsearch = TRUE;
}
/*
* Is this entry invalid?
*/
{
return (e->invalid);
}
{
return (e->time_rele);
}
/*
*/
void
{
rfs4_dbe_lock(e);
e->skipsearch = TRUE;
rfs4_dbe_unlock(e);
}
void
{
rfs4_dbe_lock(e);
e->skipsearch = FALSE;
rfs4_dbe_unlock(e);
}
void
{
mutex_enter(e->lock);
e->time_rele = gethrestime_sec();
mutex_exit(e->lock);
}
void
{
mutex_enter(e->lock);
}
void
{
mutex_exit(e->lock);
}
{
return (mutex_owned(e->lock));
}
{
}
void
{
cv_broadcast(e->cv);
}
/* ARGSUSED */
static int
{
return (0);
}
static void
{
/*LINTED*/
}
{
db->shutdown_count = 0;
return (db);
}
/*
* The reaper threads that have been created for the tables in this
* database must be stopped and the entries in the tables released.
* Each table will be marked as "shutdown" and the reaper threads
* poked and they will see that a shutdown is in progress and cleanup
* and exit. This function waits for all reaper threads to stop
* before returning to the caller.
*/
void
{
db->shutdown_count++;
}
while (db->shutdown_count > 0) {
}
}
/*
* Given a database that has been "shutdown" by the function above all
* of the table tables are destroyed and then the database itself
* freed.
*/
void
{
}
}
void (*destroy)(rfs4_entry_t),
{
int len;
char *cache_name;
char *id_name;
if (start >= 0) {
maxentries + start);
}
sizeof (rfs4_dbe_t) +
size,
0,
NULL,
NULL,
0);
return (table);
}
void
{
rfs4_table_t *p;
rfs4_index_t *t;
else {
break;
}
}
/* Destroy indices */
}
}
void *(*mkkey)(rfs4_entry_t),
{
if (createable) {
panic("Table %s currently can have only have one "
"index that will allow creation of entries",
} else {
}
return (idx);
}
void
{
}
static void
{
void *key;
int i;
rfs4_link *l;
(CE_NOTE, "Destroying entry %p from %s",
/* Unlink from all indices */
/* check and see if we were ever linked in to the index */
if (INVALID_LINK(l)) {
continue;
}
}
/* Destroy user data */
/* Destroy the entry itself */
}
static rfs4_dbe_t *
{
int i;
/*
* We mark the entry as not indexed by setting the low
* order bit, since address are word aligned. This has
* the advantage of causeing a trap if the address is
* used. After the entry is linked in to the
* corresponding index the bit will be cleared.
*/
}
return (NULL);
}
return (entry);
}
{
int already_done;
uint32_t i;
rfs4_link *l;
(CE_NOTE, "Searching for key %p in table %s by %s",
dbsearch_type == RFS4_DBS_INVALID)) &&
continue;
}
/* place an additional hold since we are returning */
rfs4_dbe_hold(l->entry);
if (entry) {
/*
* The entry has not been placed in a
* table so go ahead and drop the ref
* count and destroy the entry.
*/
}
(CE_NOTE, "Found entry %p for %p in table %s",
}
}
(CE_NOTE, "Entry for %p in %s not found",
return (NULL);
}
/* Create data before grabing an exclusive lock if needed */
(CE_NOTE, "Constructor for table %s failed",
return (NULL);
}
}
/* Now that we've allocated */
(CE_NOTE, "Trying to upgrade lock for entry %p on "
"hash chain %d (%p) for %s by %s",
goto retry;
}
/*
* Add one ref for entry into table's hash - only one
* reference added evn though there may be multiple indices
*/
continue;
ENQUEUE_IDX(bp, l);
}
(CE_NOTE, "Entry %p created for %s = %p in table %s",
}
/*ARGSUSED*/
{
rfs4_link *l;
int i;
/*
* We get called for Suspend and Resume events.
* For the suspend case we simply don't care! Nor do we care if
* there are no clients.
*/
return (B_TRUE);
}
/*
* When we get this far we are in the process of
* resuming the system from a previous suspend.
*
* We are going to blast through and update the
* last_access time for all the clients and in
* doing so extend them by one lease period.
*/
}
}
return (B_TRUE);
}
/*
* Given a table, lock each of the buckets and walk all entries (in
* turn locking those) and calling the provided "callout" function
* with the provided parameter. Obviously used to iterate across all
* entries in a particular table via the database locking hierarchy.
* Obviously the caller must not hold locks on any of the entries in
* the specified table.
*/
void
void (*callout)(rfs4_entry_t, void *),
void *data)
{
rfs4_link *l;
rfs4_dbe_t *e;
int i;
e = l->entry;
mutex_enter(e->lock);
mutex_exit(e->lock);
}
}
}
static void
{
rfs4_link *l, *t;
rfs4_dbe_t *e;
int i;
int count = 0;
(CE_NOTE,
"Reaping %d entries older than %ld seconds in table %s",
do {
e = l->entry;
/*
* Examine an entry. Ref count of 1 means
* that the only reference is for the hash
* table reference.
*/
if (e->refcnt == 1) {
mutex_enter(e->lock);
if (e->refcnt == 1) {
if (table->reaper_shutdown ||
e->refcnt--;
count++;
}
}
mutex_exit(e->lock);
}
}
if (found) {
}
while (l) {
t = l;
e = t->entry;
l = l->next;
if (e->refcnt == 0) {
INVALIDATE_ADDR(t->entry);
rfs4_dbe_destroy(e);
}
}
}
/*
* delay slightly if there is more work to do
* with the expectation that other reaper
* threads are freeing data structures as well
* and in turn will reduce ref counts on
* entries in this table allowing them to be
* released. This is only done in the
* instance that the tables are being shut down.
*/
/*
* If this is a table shutdown, keep going until
* everything is gone
*/
break;
}
(CE_NOTE,
"Reaped %d entries older than %ld seconds in table %s",
}
static void
{
callb_generic_cpr, "nfsv4Reaper");
do {
&table->reaper_cv_lock);
/* Notify the database shutdown processing that the table is shutdown */
}
static void
{
if (table->max_cache_time == 0)
return;
}
#ifdef DEBUG
void
{
}
#endif