/*
* 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 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
#include <sys/inttypes.h>
#include <sys/sysmacros.h>
#include <sys/pathname.h>
#include <sys/sunldi_impl.h>
#include <sys/ddipropdefs.h>
#include <sys/ddi_impldefs.h>
/*
* utssys()
*/
static int uts_fusers(char *, int, intptr_t);
#if defined(_ILP32) || defined(_SYSCALL32_IMPL)
{
int error;
switch (type) {
case UTS_UNAME:
/*
* This is an obsolete way to get the utsname structure
* (it only gives you the first 8 characters of each field!)
* uname(2) is the preferred and better interface.
*/
break;
case UTS_USTAT:
break;
case UTS_FUSERS:
break;
default:
break;
}
}
static int
{
return (EFAULT);
buf += 8;
return (EFAULT);
buf++;
return (EFAULT);
buf += 8;
return (EFAULT);
buf++;
return (EFAULT);
buf += 8;
return (EFAULT);
buf++;
return (EFAULT);
buf += 8;
return (EFAULT);
buf++;
return (EFAULT);
buf += 8;
return (EFAULT);
return (0);
}
static int
{
int i, error;
return (error);
/*
* Check to see if the number of free blocks can be expressed
* in 31 bits or whether the number of free files is more than
* can be expressed in 32 bits and is not -1 (UINT64_MAX). NFS
* Version 2 does not support the number of free files and
* hence will return -1. -1, when translated from a 32 bit
* quantity to an unsigned 64 bit quantity, turns into UINT64_MAX.
*/
return (EOVERFLOW);
i = 0;
if (*cp != '\0')
else
*cp2++ = '\0';
while (*cp != '\0' &&
cp++;
return (EFAULT);
return (0);
}
#endif /* _ILP32 || _SYSCALL32_IMPL */
#ifdef _LP64
{
int error;
switch (type) {
case UTS_USTAT:
break;
case UTS_FUSERS:
break;
default:
break;
}
}
static int
{
int i, error;
return (error);
i = 0;
if (*cp != '\0')
else
*cp2++ = '\0';
while (*cp != '\0' &&
cp++;
return (EFAULT);
return (0);
}
#endif /* _LP64 */
/*
* Utility routine for the ustat implementations.
* (If it wasn't for the 'find-by-dev_t' semantic of ustat(2), we could push
* this all out into userland, sigh.)
*/
static int
{
int error;
/*
* See if it's the root of our zone.
*/
} else {
}
}
return (EINVAL);
return (error);
}
/*
* Check if this pid has an NBMAND lock or share reservation
* on this vp. llp is a snapshoted list of all NBMAND locks
* set by this pid. Return 1 if there is an NBMAND lock else
* return 0.
*/
static int
{
/*
* Any NBMAND lock held by the process on this vp?
*/
while (llp) {
return (1);
}
}
/*
* Any NBMAND share reservation on the vp for this process?
*/
}
static fu_data_t *
{
int pcnt = 0;
/* get a pointer to the file system containing this vnode */
/* allocate the data structure to return our results in */
fu_data->fud_user_count = 0;
/* get a snapshot of all the pids we're going to check out */
}
/* grab each process and check its file usage */
int i, use_flag = 0;
/*
* grab prp->p_lock using sprlock()
* if sprlock() fails the process does not exists anymore
*/
continue;
/* get the processes credential info in case we need it */
/*
* it's safe to drop p_lock here because we
* called sprlock() before and it set the SPRLOCK
* flag for the process so it won't go away.
*/
/*
* now we want to walk a processes open file descriptors
* to do this we need to grab the fip->fi_lock. (you
* can't hold p_lock when grabbing the fip->fi_lock.)
*/
/*
* Snapshot nbmand locks for pid
*/
continue;
}
/*
* if the target file (fvp) is not a device
* and corrosponds to the root of a filesystem
* (cvfsp), then check if it contains the file
* is use by this process (vp).
*/
/*
* if the target file (fvp) is not a device,
* then check if it matches the file in use
* by this process (vp).
*/
/*
* if the target file (fvp) is a device,
* then check if the current file in use
* by this process (vp) maps to the same device
* minor node.
*/
if (fvp_isdev &&
/*
* if the target file (fvp) is a device,
* and we're checking for device instance
* usage, then check if the current file in use
* by this process (vp) maps to the same device
* instance.
*/
if (dip_usage &&
/*
* if the current file in use by this process (vp)
* doesn't match what we're looking for, move on
* to the next file in the process.
*/
continue;
}
/* A nbmand found so we're done. */
break;
}
}
if (llp)
/*
* If nbmand usage tracking is desired and no nbmand was
* found for this process, then no need to do further
* usage tracking for this process.
*/
/*
* grab the process lock again, clear the SPRLOCK
* flag, release the process, and continue.
*/
continue;
}
/*
* All other types of usage.
* For the next few checks we need to hold p_lock.
*/
if (fvp_isdev) {
/*
* if the target file (fvp) is a device
* then check if it matches the processes tty
*
* we grab s_lock to protect ourselves against
* freectty() freeing the vnode out from under us.
*/
if (dip_usage &&
}
} else {
/* check the processes current working directory */
/* check the processes root directory */
/* check the program text vnode */
}
/* Now we can drop p_lock again */
/*
* now we want to walk a processes memory mappings.
* to do this we need to grab the prp->p_as lock. (you
* can't hold p_lock when grabbing the prp->p_as lock.)
*/
/*
* if we can't get a backing vnode for this
* segment then skip it
*/
continue;
/*
* if the target file (fvp) is not a device
* and corrosponds to the root of a filesystem
* (cvfsp), then check if it contains the
* vnode backing this segment (vp).
*/
break;
}
/*
* if the target file (fvp) is not a device,
* check if it matches the the vnode backing
* this segment (vp).
*/
break;
}
/*
* if the target file (fvp) isn't a device,
* or the the vnode backing this segment (vp)
* isn't a device then continue.
*/
if (!fvp_isdev ||
continue;
/*
* check if the vnode backing this segment
* (vp) maps to the same device minor node
* as the target device (fvp)
*/
break;
}
/*
* if we're checking for device instance
* usage, then check if the vnode backing
* this segment (vp) maps to the same device
* instance as the target device (fvp).
*/
if (dip_usage &&
break;
}
}
}
if (use_flag) {
pcnt++;
}
/*
* grab the process lock again, clear the SPRLOCK
* flag, release the process, and continue.
*/
}
return (fu_data);
}
typedef struct dofkusers_arg {
int flags;
int *error;
static int
{
int instance;
/*
* check if the dev_t of the target device matches the dev_t
* of the device we're trying to find usage info for.
*/
/*
* if the dev_ts don't match and we're not trying
* to find usage information for device instances
* then return
*/
if (!dip_usage)
return (LDI_USAGE_CONTINUE);
/*
* we're trying to find usage information for an
* device instance instead of just a minor node.
*
* check if the dip for the target device matches the
* dip of the device we're trying to find usage info for.
*/
return (LDI_USAGE_CONTINUE);
}
return (LDI_USAGE_TERMINATE);
}
/* get the device vnode user information */
}
}
/* set the device vnode user information */
return (LDI_USAGE_CONTINUE);
}
int
{
/*
* we should only be called for f_user_t entires that represent
* a kernel file consumer
*/
return (0);
}
static fu_data_t *
{
int user_max, i;
/*
* we only keep track of kernel device consumers, so if the
* target vnode isn't a device then there's nothing to do here
*/
return (NULL);
/* allocate the data structure to return our results in */
user_max = ldi_usage_count();
fu_data->fud_user_count = 0;
/* invoke the callback to collect device usage information */
/* check for errors */
if (*error != 0)
return (fu_data);
/* if there aren't any file consumers then return */
if (fu_data->fud_user_count == 0)
return (fu_data);
/*
* since we ignore the spec_type of the target we're trying to
* access it's possible that we could have duplicates entries in
* the list of consumers.
*
* we don't want to check for duplicate in the callback because
* we're holding locks in the ldi when the callback is invoked.
*
* so here we need to go through the array of file consumers
* and remove duplicate entries.
*/
/* first sort the array of file consumers */
sizeof (f_user_t), f_user_cmp);
/* then remove any duplicate entires */
i = 1;
while (i < fu_data->fud_user_count) {
/*
* the current element is unique, move onto
* the next one
*/
i++;
continue;
}
/*
* this entry is a duplicate so if it's not the last
* entry in the array then remove it.
*/
if (i == fu_data->fud_user_count)
break;
}
return (fu_data);
}
/*
* Determine the ways in which processes and the kernel are using a named
* file or mounted file system (path). Normally return 0. In case of an
* error appropriate errno will be returned.
*
* Upon success, uts_fusers will also copyout the file usage information
* in the form of an array of f_user_t's that are contained within an
* fu_data_t pointed to by userbp.
*/
static int
{
int error = 0;
int fvp_isdev;
/* figure out how man f_user_t's we can safetly copy out */
return (EFAULT);
/*
* check if we only want a count of how many kernel device
* consumers exist
*/
if (flags & F_KINFO_COUNT) {
bcount = fu_data_size(0);
return (EFAULT);
return (0);
}
/* get the vnode for the file we want to look up usage for */
if (error != 0)
return (error);
/*
* if we want to report usage for all files contained within a
* file system then the target file better correspond to the
* root node of a mounted file system, or the root of a zone.
*/
goto out;
}
/*
* if we want to report usage for all files contained within a
* file system then the target file better not be a device.
*/
goto out;
}
/*
* if we want to report usage for a device instance then the
* target file better corrospond to a device
*/
goto out;
}
/*
* if the target vnode isn't a device and it has a reference count
* of one then no one else is going to have it open so we don't
* have any work to do.
*/
goto out;
}
/* look up usage information for this vnode */
if (error != 0)
goto out;
/* get a count of the number of f_user_t's we need to copy out */
total_out = 0;
if (fu_data)
if (fuk_data)
/* check if there is enough space to copyout all results */
goto out;
}
/* copyout file usage info counts */
bcount = fu_data_size(0);
goto out;
}
/* copyout userland process file usage info */
goto out;
}
}
/* copyout kernel file usage info */
goto out;
}
}
out:
/* release the vnode that we were looking up usage for */
/* release any allocated memory */
if (fu_data)
if (fuk_data)
return (error);
}