fem.c revision c242f9a02a2ef021449275ae0a1d2581ee77231d
/*
* 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 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/sysmacros.h>
#include <sys/vfs_opreg.h>
/*
* fl_ntob(n) - Fem_list: number of nodes to bytes
* Given the number of nodes in a fem_list return the size, in bytes,
* of the fem_list structure.
*/
((n) - 1) * sizeof (struct fem_node))
typedef enum {
FEMTYPE_NULL, /* Uninitialized */
} femtype_t;
static struct fem_type_info {
/*
* For each type, two tables - the translation offset definition, which
* is used by fs_build_vector to layout the operation(s) vector; and the
* guard_operation_vector which protects from stack under-run.
*/
int fem_err();
int fsem_err();
static fs_operation_trans_def_t fem_opdef[] = {
};
static struct fs_operation_def fem_guard_ops[] = {
};
static fs_operation_trans_def_t fsem_opdef[] = {
};
static struct fs_operation_def fsem_guard_ops[] = {
};
/*
* vsop_find, vfsop_find -
*
* These macros descend the stack until they find either a basic
* stacked item where this method is non-null [_vsop].
*
* The DEBUG one is written with a single function which manually applies
* the structure offsets. It can have additional debugging support.
*/
#ifndef DEBUG
for (;;) { \
break; \
!= NULL) { \
break; \
} else { \
} \
} \
for (;;) { \
break; \
!= NULL) { \
break; \
} else { \
} \
} \
#else
static void *
{
void *ptr;
for (;;) {
break;
!= NULL) {
break;
} else {
}
}
return (ptr);
}
#endif
static fem_t *
{
fem_t *p;
return (p);
}
void
{
kmem_free(p, sizeof (*p));
}
static fsem_t *
{
fsem_t *p;
return (p);
}
void
{
kmem_free(p, sizeof (*p));
}
/*
* fem_get, fem_release - manage reference counts on the stack.
*
* The list of monitors can be updated while operations are in
* progress on the object.
*
* The reference count facilitates this by counting the number of
* current accessors, and deconstructing the list when it is exhausted.
*
* fem_lock() is required to:
* look at femh_list
* update what femh_list points to
* update femh_list
* increase femh_list->feml_refc.
*
* the feml_refc can decrement without holding the lock;
* when feml_refc becomes zero, the list is destroyed.
*
*/
static struct fem_list *
{
return (sp);
}
static void
{
}
/*
* Addref can only be called while its head->lock is held.
*/
static void
{
}
static uint32_t
{
}
static struct fem_list *
{
fem_addref(sp);
}
fem_unlock(fp);
}
return (sp);
}
static void
{
int i;
if (fem_delref(sp) == 0) {
/*
* Before freeing the list, we need to release the
* caller-provided data.
*/
if (fnp->fn_av_rele)
}
}
}
/*
* These are the 'head' operations which perform the interposition.
*
* This set must be 1:1, onto with the (vnodeops, vfsos).
*
* If there is a desire to globally disable interposition for a particular
* method, the corresponding 'head' routine should unearth the base method
* and invoke it directly rather than bypassing the function.
*
* All the functions are virtually the same, save for names, types & args.
* 1. get a reference to the monitor stack for this object.
* 2. store the top of stack into the femarg structure.
* 3. store the basic object (vnode *, vnode **, vfs *) in the femarg struc.
* 4. invoke the "top" method for this object.
* 5. release the reference to the monitor stack.
*
*/
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
int flags)
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static void
{
void (*func)();
void *arg0;
} else {
}
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static void
{
void (*func)();
void *arg0;
} else {
}
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static void
{
void (*func)();
void *arg0;
} else {
}
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
static void
{
void (*func)();
void *arg0;
} else {
}
}
static int
{
int (*func)();
void *arg0;
int errc;
} else {
}
return (errc);
}
/*
* specification table for the vhead vnode operations.
* It is an error for any operations to be missing.
*/
static struct fs_operation_def fhead_vn_spec[] = {
};
/*
* specification table for the vfshead vnode operations.
* It is an error for any operations to be missing.
*/
static struct fs_operation_def fshead_vfs_spec[] = {
};
/*
* This set of routines transfer control to the next stacked monitor.
*
* Each routine is identical except for naming, types and arguments.
*
* The basic steps are:
* 1. Decrease the stack pointer by one.
* 2. If the current item is a base operation (vnode, vfs), goto 5.
* 3. If the current item does not have a corresponding operation, goto 1
* 4. Return by invoking the current item with the argument handle.
* 5. Return by invoking the base operation with the base object.
*
* for each classification, there needs to be at least one "next" operation
* for each "head"operation.
*
*/
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
direntflags, realpnp));
}
int
{
}
int
int flags)
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
void
{
}
int
{
}
int
{
}
void
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
void
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
void
{
}
int
{
}
/*
* Create a new fem_head and associate with the vnode.
* To keep the unaugmented vnode access path lock free, we spin
* update this - create a new one, then try and install it. If
* we fail to install, release the old one and pretend we succeeded.
*/
static struct fem_head *
{
}
return (head);
}
/*
* Create a fem_list. The fem_list that gets returned is in a
* very rudimentary state and MUST NOT be used until it's initialized
* (usually by femlist_construct() or fem_dup_list()). The refcount
* and size is set properly and top-of-stack is set to the "guard" node
* just to be consistent.
*
* If anyone were to accidentally trying to run on this fem_list before
* it's initialized then the system would likely panic trying to defererence
* the (NULL) fn_op pointer.
*
*/
static struct fem_list *
femlist_create(int numnodes)
{
return (sp);
}
/*
* Construct a new femlist.
* The list is constructed with the appropriate type of guard to
* anchor it, and inserts the original ops.
*/
static struct fem_list *
{
return (sp);
}
/*
* Duplicate a list. Copy the original list to the clone.
*
* NOTE: The caller must have the fem_head for the lists locked.
* Assuming the appropriate lock is held and the caller has done the
* math right, the clone list should be big enough to old the original.
*/
static void
{
int i;
/*
* Now that we've copied the old list (orig) to the new list (clone),
* we need to walk the new list and put another hold on fn_available.
*/
if (fnp->fn_av_hold)
}
}
static int
void **baseops,
int type,
{
void *oldops;
int retry;
int error = 0;
int i;
/* Validate the node */
return (EINVAL);
}
}
/*
* RULE: once a femhead has been pushed onto a object, it cannot be
* removed until the object is destroyed. It can be deactivated by
* placing the original 'object operations' onto the object, which
* will ignore the femhead.
* The loop will exist when the femh_list has space to push a monitor
* onto it.
*/
do {
retry = 1;
retry = 0;
} else {
fem_unlock(hd);
if (list->feml_ssize <=
olist->feml_ssize) {
/*
* We have a new list, but it
* is too small to hold the
* original contents plus the
* one to push. Release the
* new list and start over.
*/
fem_unlock(hd);
} else {
/*
* Life is good: Our new list
* is big enough to hold the
* original list (olist) + 1.
*/
/* orphan this list */
(void) fem_delref(olist);
retry = 0;
}
} else {
/* concurrent update, retry */
fem_unlock(hd);
}
/* remove the reference we added above */
}
} else {
fem_unlock(hd);
/* concurrent update, retry */
fem_unlock(hd);
} else {
retry = 0;
}
}
} while (retry);
/*
* nodes are pushed. If it's FORCE, then we can skip
* all the checks and push it on.
*/
/* Start at the top and work our way down */
/*
* OPARGUNIQ means that this node should not
* combination exists. This situation returns
* EBUSY.
*
* OPUNIQ means that this node should not be
* pushed on if a node with the same op exists.
* This situation also returns EBUSY.
*/
switch (how) {
case OPUNIQ:
}
break;
case OPARGUNIQ:
}
break;
default:
break;
}
if (error)
break;
}
}
if (error == 0) {
/*
* If no errors, slap the node on the list.
* Note: The following is a structure copy.
*/
}
fem_unlock(hd);
return (error);
}
/*
* Remove a node by copying the list above it down a notch.
* If the list is busy, replace it with an idle one and work
* upon it.
* A node matches if the opset matches and the datap matches or is
* null.
*/
static int
{
int i;
break;
}
}
if (i == 0) {
return (EINVAL);
}
/*
* At this point we have a node in-hand (*fn) that we are about
* to remove by overwriting it and adjusting the stack. This is
* our last chance to do anything with this node so we do the
* release on the arg.
*/
if (fn->fn_av_rele)
}
}
return (0);
}
static int
{
int error = 0;
int retry;
return (EINVAL);
}
do {
retry = 0;
fem_unlock(fh);
/*
* The top-of-stack was decremented by
* remove_node(). If it got down to 1,
* then the base ops were replaced and we
* call fem_release() which will free the
* fem_list.
*/
/* XXX - Do we need a membar_producer() call? */
}
fem_unlock(fh);
} else {
/* busy - install a new one without this monitor */
fem_addref(sp);
fem_unlock(fh);
/*
* We popped out of the lock, created a
* list, then relocked. If we're in here
* then the fem_head points to the same list
* it started with.
*/
if (error != 0) {
/* New list now empty, tear it down */
} else {
}
(void) fem_delref(sp);
} else {
/* List changed while locked, try again... */
retry = 1;
}
/*
* If error is set, then we tried to remove a node
* from the list, but failed. This means that we
* will still be using this list so don't release it.
*/
if (error == 0)
fem_unlock(fh);
}
} while (retry);
return (error);
}
/*
* perform operation on each element until one returns non zero
*/
static int
int (*f)(struct fem_node *, void *, void *),
void *mon,
void *arg)
{
int i;
break;
}
}
return (i);
}
/*
* companion comparison functions.
*/
static int
{
}
/*
* VNODE interposition.
*/
int
{
int unused_ops = 0;
int e;
if (e != 0) {
#ifdef DEBUG
#endif
} else {
}
return (e);
}
int
void *arg, /* Opaque data used by monitor */
void (*arg_hold)(void *), /* Hold routine for "arg" */
void (*arg_rele)(void *)) /* Release routine for "arg" */
{
int error;
/*
* If we have a non-NULL hold function, do the hold right away.
* The release is done in remove_node().
*/
if (arg_hold)
/* If there was an error then the monitor wasn't pushed */
return (error);
}
int
{
int e;
return (e);
}
return (0);
}
int
{
int e;
return (e);
}
void
{
vnodeops_t *r;
do {
r = v->v_op;
fem_unlock(v->v_femhead);
return;
}
fem_unlock(v->v_femhead);
}
}
fem_getvnops(vnode_t *v)
{
vnodeops_t *r;
r = v->v_op;
}
fem_unlock(v->v_femhead);
}
return (r);
}
/*
* VFS interposition
*/
int
{
int unused_ops = 0;
int e;
newv = fsem_alloc();
if (e != 0) {
#ifdef DEBUG
#endif
} else {
}
return (e);
}
/*
* These need to be re-written, but there should be more common bits.
*/
int
{
return (0);
int e;
return (e);
}
return (0);
}
int
void *arg, /* Opaque data used by monitor */
void (*arg_hold)(void *), /* Hold routine for "arg" */
void (*arg_rele)(void *)) /* Release routine for "arg" */
{
int error;
/* If this vfs hasn't been properly initialized, fail the install */
return (EINVAL);
/*
* If we have a non-NULL hold function, do the hold right away.
* The release is done in remove_node().
*/
if (arg_hold)
/* If there was an error then the monitor wasn't pushed */
return (error);
}
int
{
int e;
return (EINVAL);
return (e);
}
void
{
vfsops_t *r;
do {
r = v->vfs_op;
if (v->vfs_femhead != NULL) {
fem_unlock(v->vfs_femhead);
return;
}
fem_unlock(v->vfs_femhead);
}
}
vfsops_t *
fsem_getvfsops(vfs_t *v)
{
vfsops_t *r;
r = v->vfs_op;
if (v->vfs_femhead != NULL) {
}
fem_unlock(v->vfs_femhead);
}
return (r);
}
/*
* Setup FEM.
*/
void
fem_init()
{
struct fem_type_info *fi;
/*
* This femtype is only used for fem_list creation so we only
* need the "guard" to be initialized so that feml_tos has
* some rudimentary meaning. A fem_list must not be used until
* it has been initialized (either via femlist_construct() or
* fem_dup_list()). Anything that tries to use this fem_list
* before it's actually initialized would panic the system as
* soon as "fn_op" (NULL) is dereferenced.
*/
}
int
fem_err()
{
return (0);
}
int
fsem_err()
{
return (0);
}