port_fop.c revision 31ceb98b622e1a310256f4c4a1472beb92046db3
/*
* 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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* File Events Notification
* ------------------------
*
* The File Events Notification facility provides file and directory change
* notification. It is implemented as an event source(PORT_SOURCE_FILE)
* under the Event Ports framework. Therefore the API is an extension to
* the Event Ports API.
*
* It uses the FEM (File Events Monitoring) framework to intercept
* operations on the files & directories and generate appropriate events.
*
* It provides event notification in accordance with what an application
* can find out by stat`ing the file and comparing time stamps. The various
* system calls that update the file's access, modification, and change
* time stamps are documented in the man page section 2.
*
* It is non intrusive. That is, having an active file event watch on a file
* or directory will not prevent it from being removed or renamed or block an
* unmount operation of the file system where the watched file or directory
* resides.
*
*
* Interface:
* ----------
*
* The object for this event source is of type 'struct file_obj *'
*
* The file that needs to be monitored is specified in 'fo_name'.
* The time stamps collected by a stat(2) call are passed in fo_atime,
* fo_mtime, fo_ctime. At the time a file events watch is registered, the
* time stamps passed in are compared with the current time stamps of the
* file. If it has changed, relavant events are sent immediately. If the time
* stamps are all '0', they will not be compared.
*
*
* The events are delivered to an event port. A port is created using
* port_create().
*
* To register a file events watch on a file or directory.
*
* port_associate(int port, PORT_SOURCE_FILE, (uintptr_t)&fobj, events, user)
*
* 'user' is the user pointer to be returned with the event.
*
* To de-register a file events watch,
*
* port_dissociate(int port, PORT_SOURCE_FILE, (uintptr_t)&fobj)
*
* The events are collected using the port_get()/port_getn() interface. The
* event source will be PORT_SOURCE_FILE.
*
* After an event is delivered, the file events watch gets de-activated. To
* receive the next event, the process will have to re-register the watch and
* activate it by calling port_associate() again. This behavior is intentional
* and support proper multi threaded programming when using file events
* notification API.
*
*
* Implementation overview:
* ------------------------
*
* Each file events watch is represented by 'portfop_t' in the kernel. A
* cache(portfop_cache_t) of these file portfop_t's are maintained per event
* port by this source. The object here is the pointer to the file_obj
* structure. The portfop_t's are hashed in using the object pointer. Therefore
* it is possible to have multiple file event watches on a file by the same
* process by using different object structure(file_obj_t) and hence can
* receive multiple event notification for a file. These watches can be for
* different event types.
*
* The cached entries of these file objects are retained, even after delivering
* an event makring them inactive, for performance reason. The assumption
* is that the process would come back and re-register the file to receive
* further events. When there are more then 'port_fop_maxpfps' watches per file
* it will attempt to free the oldest inactive watch.
*
* In case the event that is being delivered is an exception event, the cached
* entries get removed. An exception event on a file or directory means its
* unmount).
*
* If the event port gets closed, all the associated file event watches will be
* removed and discarded.
*
*
* Data structures:
* ----------------
*
* The list of file event watches per file are managed by the data structure
* portfop_vp_t. The first time a file events watch is registered for a file,
* the portfop_vp_t is installed on the vnode_t's member v_fopdata. This gets
* removed and freed only when the vnode becomes inactive. The FEM hooks are
* also installed when the first watch is registered on a file. The FEM hooks
* get un-installed when all the watches are removed.
*
* Each file events watch is represented by the structure portfop_t. They
* get added to a list of portfop_t's on the vnode(portfop_vp_t). After
* delivering an event, the portfop_t is marked inactive but retained. It is
* moved to the end of the list. All the active portfop_t's are maintained at
* the beginning. In case of exception events, the portfop_t will be removed
* and discarded.
*
* To intercept unmount operations, FSEM hooks are added to the file system
* under which files are being watched. A hash table('portfop_vfs_hash_t') of
* active file systems is maintained. Each file system that has active watches
* is represented by 'portfop_vfs_t' and is added to the hash table.
* The vnode's 'portfop_vp_t' structure is added to the list of files(vnodes)
* being watched on the portfop_vfs_t structure.
*
*
* File system support:
* -------------------
*
* The file systems implementation has to provide vnode event notifications
* (vnevents) in order to support watching any files on that file system.
* The vnode events(vnevents) are notifications provided by the file system
* for name based file operations like rename, remove etc, which do not go
* thru the VOP_** interfaces. If the file system does not implement vnode
* notifications, watching for file events on such file systems is not
* supported. The vnode event notifications support is determined by the call
* vnevent_support(vp) (VOP_VNEVENT(vp, VE_SUPPORT)), which the file system
* has to implement.
*
*
* Locking order:
* --------------
*
* A file(vnode) can have file event watches registered by different processes.
* There is one portfop_t per watch registered. These are on the vnode's list
* protected by the mutex 'pvp_mutex' in 'portfop_vp_t'. The portfop_t's are
* also on the per port cache. The cache is protected by the pfc_lock of
* portfop_cache_t. The lock order here is 'pfc_lock' -> 'pvp_mutex'.
*
*/
#include <sys/sysmacros.h>
#include <sys/poll_impl.h>
#include <sys/port_impl.h>
#include <sys/vfs_opreg.h>
/*
*/
extern struct vnode *mntdummyvp;
extern int mntfstype;
/*
* Inactive file event watches(portfop_t) are retained on the vnode's list
* for performance reason. If the applications re-registers the file, the
* inactive entry is made active and moved up the list.
*
* If there are greater then the following number of watches on a vnode,
* it will attempt to discard an oldest inactive watch(pfp) at the time
* a new watch is being registerd and when events get delivered. We
* do this to avoid accumulating inactive watches on a file.
*/
int port_fop_maxpfps = 20;
/* local functions */
static int port_fop_callback(void *, int *, pid_t, int, void *);
/*
* port fop functions that will be the fem hooks.
*/
struct caller_context *ct);
int flag);
char *cname);
/*
* Fem hooks.
*/
const fs_operation_def_t port_vnodesrc_template[] = {
};
/*
* Fsem - vfs ops hooks
*/
const fs_operation_def_t port_vfssrc_template[] = {
};
static fem_t *
{
return (fop_femop);
if (fem_create("portfop_fem",
(const struct fs_operation_def *)port_vnodesrc_template,
return (NULL);
}
/*
* some other thread beat us to it.
*/
}
return (fop_femop);
}
static fsem_t *
{
if (fop_fsemop != NULL)
return (fop_fsemop);
return (NULL);
}
/*
* some other thread beat us to it.
*/
}
return (fop_fsemop);
}
/*
* port_fop_callback()
* - PORT_CALLBACK_DEFAULT
* The file event will be delivered to the application.
* - PORT_CALLBACK_DISSOCIATE
* The object will be dissociated from the port.
* - PORT_CALLBACK_CLOSE
* The object will be dissociated from the port because the port
* is being closed.
*/
/* ARGSUSED */
static int
{
int error = 0;
if (flag == PORT_CALLBACK_DEFAULT) {
return (EACCES); /* deny delivery of events */
}
pkevp->portkev_events = 0;
}
}
return (error);
}
/*
* Inserts a portfop_t into the port sources cache's.
*/
static void
{
pfcp->pfc_objcount++;
}
/*
* Remove the pfp from the port source cache.
*/
static void
{
} else {
/* portfop struct found */
break;
}
}
}
pfcp->pfc_objcount--;
}
/*
* The vnode's(portfop_vp_t) pfp list management. The 'pvp_mutex' is held
* when these routines are called.
*
* The 'pvp_lpfop' member points to the oldest inactive entry on the list.
* It is used to discard the oldtest inactive pfp if the number of entries
* exceed the limit.
*/
static void
{
if (where == 1) {
} else {
}
}
}
static void
{
}
static void
{
/*
* We point lpfop to an inactive one, if it was initially pointing
* to an active one. Insert to the tail is done only when a pfp goes
* inactive.
*/
}
}
static void
{
}
}
}
static void
{
}
/*
* Remove a portfop_t from the port cache hash table and discard it.
* It is called only when pfp is not on the vnode's list. Otherwise,
* port_remove_fop() is called.
*/
void
{
(void) port_remove_done_event(pkevp);
}
if (pfcp->pfc_objcount == 0)
}
/*
* if we have too many watches on the vnode, attempt to discard an
* inactive one.
*/
static void
{
/*
* Due to a reference the vnode cannot disappear, v_fopdata should
* not change.
*/
/*
* only if we can get the cache lock, we need to
* do this due to reverse lock order and some thread
* that may be trying to reactivate this entry.
*/
} else {
}
} else {
}
/*
* discard pfp if any.
*/
}
}
}
void
{
/*
* if list is empty, uninstall fem.
*/
/*
* make sure the list is empty.
*/
/*
* we could possibly uninstall the fem hooks when
* the vnode becomes inactive and the v_fopdata is
* free. But the hooks get triggered uncessarily
* even though there are no active watches. So, we
* uninstall it here.
*/
/*
* If we uinstalled fem means no process is watching this
* vnode, remove it from the vfs's list of watched vnodes.
*/
/*
* If unmount is in progress, that thread will remove and
* release the vnode from the vfs's list, just leave.
*/
if (!pvfsp->pvfs_unmount) {
} else {
}
} else {
}
}
/*
* Remove pfp from the vnode's watch list and the cache and discard it.
* If it is the last pfp on the vnode's list, the fem hooks get uninstalled.
* Returns 1 if removed successfully.
*
* The *active is set to indicate if the pfp was still active(no events had
* been posted, or the posted event had not been collected yet and it was
* able to remove it from the port's queue).
*/
int
int *active)
{
int tactive = 0;
/*
* if not cleanup, remove it only if the pfp is still active and
* is not being removed by some other thread.
*/
return (0);
}
/*
* mark it inactive.
*/
tactive = 1;
}
/*
* Check if the pfp is still on the vnode's list. This can
* happen if port_fop_excep() is in the process of removing it.
* In case of cleanup, just mark this pfp as inactive so that no
* new events (VNEVENT) will be delivered, and remove it from the
* event queue if it was already queued. Since the cache lock is
* held, the pfp will not disappear, even though it is being
* removed.
*/
tactive = 1;
}
if (active) {
}
return (1);
}
/*
* if we find an event on the queue and removed it, then this
* association is considered active.
*/
tactive = 1;
}
if (active) {
}
/*
* remove pfp from the vnode's list
*/
/*
* If no more associations on the vnode, uninstall fem hooks.
* The pvp mutex will be released in this routine.
*/
return (1);
}
/*
* This routine returns a pointer to a cached portfop entry, or NULL if it
* does not find it in the hash table. The object pointer is used as index.
* The entries are hashed by the object's address. We need to match the pid
* as the evet port can be shared between processes. The file events
* watches are per process only.
*/
{
break;
}
return (pfp);
}
/*
* Given the file name, get the vnode and also the directory vnode
* On return, the vnodes are held (VN_HOLD). The caller has to VN_RELE
* the vnode(s).
*/
int
{
int error = 0;
char *fname;
if (get_udatamodel() == DATAMODEL_NATIVE) {
#ifdef _SYSCALL32_IMPL
} else {
#endif /* _SYSCALL32_IMPL */
}
/*
* lookuppn may fail with EINVAL, if dvp is non-null(like when
* looking for "."). So call again with dvp = NULL.
*/
return (error);
}
return (error);
}
}
}
pn_setlast(&pn);
} else {
*len = 0;
}
}
return (error);
}
{
int lock = 0;
/*
* get the port source structure.
*/
lock = 1;
}
break;
}
if (lock) {
}
return (pse);
}
/*
* compare time stamps and generate an event if it has changed.
*/
static void
{
int events = 0;
/*
* some event got delivered, don't bother with
* checking the timestamps.
*/
return;
}
/*
* If time stamps is specified, get attributes and compare. This
* needs to be done after registering. We should check if any
* timestamps have been specified before getting attr XXX.
*/
if (get_udatamodel() == DATAMODEL_NATIVE) {
return;
}
} else {
/*
* timestamp not specified, all 0's,
*/
return;
}
#ifdef _SYSCALL32_IMPL
} else {
return;
}
} else {
/*
* timestamp not specified, all 0.
*/
return;
}
#endif /* _SYSCALL32_IMPL */
}
/*
* The pfp cannot dissappear as the port cache lock is held.
* While the pvp_mutex is held, no events will get delivered.
*/
if (get_udatamodel() == DATAMODEL_NATIVE) {
events |= FILE_ACCESS;
events |= FILE_MODIFIED;
events |= FILE_ATTRIB;
#ifdef _SYSCALL32_IMPL
} else {
events |= FILE_ACCESS;
events |= FILE_MODIFIED;
events |= FILE_ATTRIB;
#endif /* _SYSCALL32_IMPL */
}
/*
* No events to deliver
*/
if (events == 0) {
return;
}
/*
* Deliver the event now.
*/
/*
* Move it to the tail as active once are in the
* begining of the list.
*/
}
}
/*
* Add the event source to the port and return the port source cache pointer.
*/
int
{
int error;
/*
* associate PORT_SOURCE_FILE source with the port, if it is
* not associated yet. Note the PORT_SOURCE_FILE source is
* associated once and will not be dissociated.
*/
return (error);
}
}
/*
* Get the portfop cache pointer.
*/
/*
* This is the first time that a file is being associated,
* create the portfop cache.
*/
} else {
/*
* someone else created the port cache, free
* what we just now allocated.
*/
}
}
return (0);
}
/*
* Add the given pvp on the file system's list of vnodes watched.
*/
int
{
int error = 0;
;
if (!pvfsp) {
return (error);
}
} else {
return (EINVAL);
}
}
/*
* check if an unmount is in progress.
*/
if (!pvfsp->pvfs_unmount) {
/*
* insert the pvp on list.
*/
} else {
}
return (error);
}
/*
* Installs the portfop_vp_t data structure on the
* vnode. The 'pvp_femp == NULL' indicates it is not
* active. The fem hooks have to be installed.
* The portfop_vp_t is only freed when the vnode gets freed.
*/
void
{
/*
* If v_fopdata is not null, some other thread beat us to it.
*/
}
}
/*
* Allocate and add a portfop_t to the per port cache. Also add the portfop_t
* to the vnode's list. The association is identified by the object pointer
* address and pid.
*/
int
{
int error = 0;
/*
* The port cache mutex is held.
*/
/*
* At this point the fem monitor is installed.
* Allocate a port event structure per vnode association.
*/
PORT_ALLOC_CACHED, &pkevp)) {
return (error);
}
}
pkevp->portkev_events = 0;
/*
* Register a new file events monitor for this file(vnode), if not
* done already.
*/
}
/*
* if the vnode does not have the file events hooks, install it.
*/
/*
* add fsem_t hooks to the vfsp and add pvp to
* the list of vnodes for this vfs.
*/
/*
* Hold a reference to the vnode since
* we successfully installed the hooks.
*/
} else {
}
}
} else {
}
}
if (error) {
/*
* pkevp will get freed here.
*/
return (error);
}
/*
* insert the pfp on the vnode's list. After this
* events can get delivered.
*/
return (0);
}
vnode_t *
{
/*
* file that can exist.
*/
vp = mntdummyvp;
}
/*
* This should take care of lofs mounted fs systems and nfs4
* hardlinks.
*/
}
return (vp);
}
/*
* Register a file events watch on the given file associated to the port *pp.
*
* The association is identified by the object pointer and the pid.
* The events argument contains the events to be monitored for.
*/
int
void *user)
{
int error = 0;
void *objptr;
char *cname;
int clen;
int removing = 0;
int follow;
/*
* check that events specified are valid.
*/
if ((events & ~FILE_EVENTS_MASK) != 0)
return (EINVAL);
if (get_udatamodel() == DATAMODEL_NATIVE) {
return (EFAULT);
#ifdef _SYSCALL32_IMPL
} else {
return (EFAULT);
#endif /* _SYSCALL32_IMPL */
}
/*
* findout if we need to follow symbolic links.
*/
/*
* lookup and find the vnode and its directory vnode of the given
* file.
*/
follow)) != 0) {
return (error);
}
}
/*
* Not found
*/
goto errout;
}
goto errout;
}
/*
* Associate this source to the port and get the per port
* fop cache pointer. If the source is already associated, it
* will just return the cache pointer.
*/
goto errout;
}
/*
* Check if there is an existing association of this file.
*/
/*
* if it is not the same vnode, just discard it.
*/
}
/*
* Add a new association, save the file name and the
* directory vnode pointer.
*/
goto errout;
}
/*
* File name used, so make sure we don't free it.
*/
/*
* We need to check if the file was removed after the
* the lookup and before the fem hooks where added. If
* so, return error. The vnode will still exist as we have
* a hold on it.
*/
int error;
}
}
/*
* remove the pfp and fem hooks, if pfp still
* active and it is not being removed from
* the vnode list. This is checked in
* port_remove_fop with the vnode lock held.
*/
/*
* the pfp was removed, means no
* events where queued. Report the
* error now.
*/
goto errout;
}
} else {
}
}
} else {
/*
* Re-association of the object.
*/
/*
* remove any queued up event.
*/
}
/*
* set new events to watch.
*/
/*
* check if this pfp is being removed. Port_fop_excep()
* will deliver an exception event.
*/
removing = 1;
}
/*
* If not active, mark it active even if it is being
* removed. Then it can send an exception event.
*
* Move it to the head, as the active ones are only
* in the begining. If removing, the pfp will be on
* a temporary list, no need to move it to the front
* all the entries will be processed.
*/
if (!removing) {
}
}
}
/*
* compare time stamps and deliver events. The pfp cannot
* dissappear since we are holding the cache lock.
*/
}
error = 0;
/*
* If we have too many watches on the vnode, discard an
* inactive watch.
*/
/*
* Release the hold acquired due to the lookup operation.
*/
/*
* copied file name not used, free it.
*/
}
return (error);
}
/*
* The port_dissociate_fop() function dissociates the file object
* from the event port and removes any events that are already on the queue.
* Only the owner of the association is allowed to dissociate the file from
* the port. Returns success (0) if it was found and removed. Otherwise
* ENOENT.
*/
int
{
int active = 0;
/*
* if this source is not associated or if there is no
* cache, nothing to do just return.
*/
return (EINVAL);
/*
* Check if this object is on the cache. Only the owner pid
* is allowed to dissociate.
*/
return (ENOENT);
}
/*
* If this was the last association, it will release
* the hold on the vnode. There is a race condition where
* the the pfp is being removed due to an exception event
* in port_fop_sendevent()->port_fop_excep() and port_remove_fop().
* Since port source cache lock is held, port_fop_excep() cannot
* complete. And the vnode itself will not dissapear as long pfp's
* have a reference.
*/
}
/*
* port_close() calls this function to request the PORT_SOURCE_FILE source
*/
/* ARGSUSED */
static void
{
int index;
/*
* No source or no cache, nothing to do.
*/
return;
/*
* Scan the cache and free all allocated portfop_t and port_kevent_t
* structures of this pid.
*/
}
}
}
/*
* Due to a race between port_close_fop() and port_fop()
* trying to remove the pfp's from the port's cache, it is
* possible that some pfp's are still in the process of being
* freed so we wait.
*/
}
/*
* last close, free the cache.
*/
if (lastclose) {
}
}
/*
* Given the list of associations(watches), it will send exception events,
* if still active, and discard them. The exception events are handled
* seperately because, the pfp needs to be removed from the port cache and
* freed as the vnode's identity is changing or being removed. To remove
* the pfp from the port's cache, we need to hold the cache lock (pfc_lock).
* The lock order is pfc_lock -> pvp_mutex(vnode's) mutex and that is why
* the cache's lock cannot be acquired in port_fop_sendevent().
*/
static void
{
int error = 0;
int removed = 0;
/*
* remove from the temp list. Since PORT_FOP_REMOVING is
* set, no other thread should attempt to perform a
* list_remove on this pfp.
*/
/*
* Remove the event from the port queue if it was queued up.
* No need to clear the PORT_FOP_KEV_ONQ flag as this pfp is
* no longer on the vnode's list.
*/
}
/*
* If still active or the event was queued up and
* had not been collected yet, send an EXCEPTION event.
*/
/*
* Allocate a port_kevent_t non cached to send this
* event since we will be de-registering.
* The port_kevent_t cannot be pointing back to the
* pfp anymore.
*/
if (!error) {
/*
* Copy the pid of the watching process.
*/
pkevp->portkev_pid =
}
}
/*
* At this point the pfp has been removed from the vnode's
* list its cached port_kevent_t is not on the done queue.
* Remove the pfp and free it from the cache.
*/
}
}
/*
* Send the file events to all of the processes watching this
* vnode. In case of hard links, the directory vnode pointer and
* the file name are compared. If the names match, then the specified
* event is sent or else, the FILE_ATTRIB event is sent, This is the
* documented behavior.
*/
void
{
int removeall = 0;
/*
* Check if the list is empty.
*
* All entries have been removed by some other thread.
* The vnode may be still active and we got called,
* but some other thread is in the process of removing the hooks.
*/
return;
}
if ((events & (FILE_EXCEPTION))) {
/*
* If it is an event for which we are going to remove
* the watches so just move it a temporary list and
* release this vnode.
*/
/*
* If it is an UNMOUNT, MOUNTEDOVER or no file name has been
* passed for an exception event, all associations need to be
* removed.
*/
removeall = 1;
}
}
if (!removeall) {
/*
* All the active ones are in the begining of the list.
*/
/*
* Hard links case - If the file is being
* the watched file, then it is an EXCEPTION
* event or else it will be just a FILE_ATTRIB.
*/
if ((events & (FILE_EXCEPTION))) {
/*
* It is an exception event, move it
* to temp list and process it later.
* Note we don't set the pfp->pfop_vp
* to NULL even thought it has been
* removed from the vnode's list. This
* pointer is referenced in
* port_remove_fop(). The vnode it
* self cannot dissapear until this
* pfp gets removed and freed.
*/
continue;
} else {
}
}
/*
* deactivate and move it to the tail.
* If the pfp was active, it cannot be
* on the port's done queue.
*/
pkevp->portkev_events |=
}
}
}
if ((events & (FILE_EXCEPTION))) {
if (!removeall) {
/*
* Check the inactive associations and remove them if
* the file name matches.
*/
}
}
} else {
/*
* Can be optimized to avoid two pass over this list
* by having a flag in the vnode's portfop_vp_t
* structure to indicate that it is going away,
* Or keep the list short by reusing inactive watches.
*/
}
}
/*
* Uninstall the fem hooks if there are no more associations.
* This will release the pvp mutex.
*
* Even thought all entries may have been removed,
* the vnode itself cannot disappear as there will be a
* hold on it due to this call to port_fop_sendevent. This is
* important to syncronize with a port_dissociate_fop() call
* that may be attempting to remove an object from the vnode's.
*/
/*
* Send exception events and discard the watch entries.
*/
} else {
/*
* contain the list size.
*/
}
}
/*
* Given the file operation, map it to the events types and send.
*/
void
{
int event = 0;
/*
* deliver events only if the operation was successful.
*/
if (retval)
return;
/*
* These events occuring on the watched file.
*/
if (op & FOP_MODIFIED_MASK) {
}
if (op & FOP_ACCESS_MASK) {
event |= FILE_ACCESS;
}
if (op & FOP_ATTRIB_MASK) {
event |= FILE_ATTRIB;
}
if (event) {
}
}
/*
* ----- the unmount filesystem op(fsem) hook.
*/
int
{
int error;
/*
* since this fsem hook is triggered, tit has to be on
* the hash list.
*/
;
/*
* Indicate that the unmount is in process. Don't remove it yet.
* The underlying filesystem unmount routine sets the VFS_UNMOUNTED
* flag on the vfs_t structure. But we call the filesystem unmount
* routine after removing all the file watches for this filesystem,
* otherwise the unmount will fail due to active vnodes.
* Meanwhile setting pvfsp->unmount = 1 will prevent any thread
* attempting to add a file watch.
*/
/*
* uninstall the fsem hooks.
*/
/*
* This should send an UNMOUNTED event to all the
* watched vnode of this filesystem and uninstall
* the fem hooks. We release the hold on the vnode here
* because port_fop_femuninstall() will not do it if
* unmount is in process.
*/
}
/*
* we free the pvfsp after the unmount has been completed.
*/
;
/*
* remove and free it.
*/
if (*ppvfsp) {
}
return (error);
}
/*
* ------------------------------file op hooks--------------------------
* The O_TRUNC operation is caught with the VOP_SETATTR(AT_SIZE) call.
*/
static int
{
int retval;
return (retval);
}
static int
{
int retval;
return (retval);
}
static int
{
int retval;
return (retval);
}
static int
{
int retval;
return (retval);
}
/*
* AT_SIZE - is for the open(O_TRUNC) case.
*/
int
{
int retval;
int events = 0;
}
}
}
return (retval);
}
int
{
/*
* If the file already exists, then there will be no change
* to the directory. Therefore, we need to compare the
* modification time of the directory to determine if the
* file was actually created.
*/
got = 0;
}
/*
* File was created.
*/
}
}
return (retval);
}
int
{
int retval;
return (retval);
}
int
{
int retval;
return (retval);
}
/*
* Rename operation is allowed only when from and to directories are
* on the same filesystem. This is checked in vn_rename().
* The target directory is notified thru a VNEVENT by the filesystem
* if the source dir != target dir.
*/
int
{
int retval;
return (retval);
}
int
{
int retval;
return (retval);
}
int
{
int retval;
return (retval);
}
int
{
int retval;
return (retval);
}
int
{
int retval;
return (retval);
}
/*
* acl, facl call this.
*/
int
{
int retval;
return (retval);
}
/*
*/
int
{
switch (vnevent) {
case VE_RENAME_SRC:
break;
case VE_RENAME_DEST:
break;
case VE_REMOVE:
break;
case VE_RMDIR:
break;
case VE_CREATE:
break;
case VE_LINK:
break;
case VE_RENAME_DEST_DIR:
break;
case VE_MOUNTEDOVER:
break;
default:
break;
}
}