nfs4_db.c revision f6cf9e5015c0407e421e650c54e2cc47c8ea3546
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#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 *);
/*
*/
{
}
void
{
}
/*
* rfs4_dbe_rele_nolock only decrements the reference count of the entry.
*/
void
{
}
{
return (entry->dbe_refcnt);
}
/*
* Mark an entry such that the dbsearch will skip it.
* Caller does not want this entry to be found any longer
*/
void
{
}
/*
* Is this entry invalid?
*/
{
return (entry->dbe_invalid);
}
{
return (entry->dbe_time_rele);
}
/*
*/
void
{
}
void
{
}
void
{
}
void
{
}
void
{
}
{
}
{
}
void
{
}
/* ARGSUSED */
static int
{
return (0);
}
static void
{
/*LINTED*/
}
{
db->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->db_shutdown_count++;
}
while (db->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;
table->dbt_idxcnt = 0;
if (start >= 0) {
maxentries + start);
}
0,
NULL,
NULL,
0);
return (table);
}
void
{
rfs4_table_t *p;
else {
break;
}
}
/* Destroy indices */
while (table->dbt_indices) {
}
if (table->dbt_id_space)
}
void *(*mkkey)(rfs4_entry_t),
{
table->dbt_idxcnt++;
if (createable) {
panic("Table %s currently can have only have one "
"index that will allow creation of entries",
} else {
}
KM_SLEEP);
return (idx);
}
void
{
}
static void
{
void *key;
int i;
rfs4_link_t *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 */
if (table->dbt_destroy)
if (table->dbt_id_space)
/* Destroy the entry itself */
}
static rfs4_dbe_t *
{
int i;
entry->dbe_time_rele = 0;
if (table->dbt_id_space)
for (i = 0; i < table->dbt_maxcnt; 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);
}
static void
{
/*
* Adjust the table's reap interval based on the
* number of id's currently in use. Each table's
* default remains the same if id usage subsides.
*/
} else {
}
DTRACE_PROBE2(table__reap__interval, char *,
}
{
int already_done;
uint32_t i;
rfs4_link_t *l;
(CE_NOTE, "Searching for key %p in table %s by %s",
if (l->entry->dbe_refcnt > 0 &&
dbsearch_type == RFS4_DBS_INVALID)) &&
if (l->entry->dbe_refcnt == 0) {
continue;
}
/* place an additional hold since we are returning */
rfs4_dbe_hold(l->entry);
(CE_NOTE, "Found entry %p for %p in table %s",
if (id != -1)
}
}
(CE_NOTE, "Entry for %p in %s not found",
if (id != -1)
return (NULL);
}
/* get an id, ok to sleep for it here */
goto retry;
}
/* get an exclusive lock on the bucket */
(CE_NOTE, "Trying to upgrade lock on "
"hash chain %d (%p) for %s by %s",
goto retry;
}
/* create entry */
if (id != -1)
(CE_NOTE, "Constructor for table %s failed",
return (NULL);
}
/*
* Add one ref for entry into table's hash - only one
* reference added even 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_t *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_t *l;
int i;
}
}
}
static void
{
rfs4_link_t *l, *t;
int i;
int count = 0;
(CE_NOTE, "Reaping %d entries older than %ld seconds in table %s",
do {
/*
* Examine an entry. Ref count of 1 means
* that the only reference is for the hash
* table reference.
*/
continue;
(table->dbt_reaper_shutdown ||
entry->dbe_refcnt--;
count++;
}
}
if (found) {
}
while (l) {
t = l;
l = l->next;
if (entry->dbe_refcnt == 0) {
INVALIDATE_ADDR(t->entry);
}
}
}
/*
* 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 {
/* Notify the database shutdown processing that the table is shutdown */
}
static void
{
if (table->dbt_max_cache_time == 0)
return;
}
#ifdef DEBUG
void
{
}
#endif