don't bother resolving onbld python module deps
[unleashed.git] / kernel / syscall / utssys.c
blob10b3d078ad9a9c3059976dfc64e23a654013458a
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
24 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
29 /* All Rights Reserved */
32 #include <sys/param.h>
33 #include <sys/inttypes.h>
34 #include <sys/types.h>
35 #include <sys/sysmacros.h>
36 #include <sys/systm.h>
37 #include <sys/user.h>
38 #include <sys/errno.h>
39 #include <sys/vfs.h>
40 #include <sys/vnode.h>
41 #include <sys/file.h>
42 #include <sys/proc.h>
43 #include <sys/session.h>
44 #include <sys/var.h>
45 #include <sys/utsname.h>
46 #include <sys/utssys.h>
47 #include <sys/ustat.h>
48 #include <sys/statvfs.h>
49 #include <sys/kmem.h>
50 #include <sys/debug.h>
51 #include <sys/pathname.h>
52 #include <sys/modctl.h>
53 #include <sys/fs/snode.h>
54 #include <sys/sunldi_impl.h>
55 #include <sys/ddi.h>
56 #include <sys/sunddi.h>
57 #include <sys/cmn_err.h>
58 #include <sys/ddipropdefs.h>
59 #include <sys/ddi_impldefs.h>
60 #include <sys/modctl.h>
61 #include <sys/flock.h>
62 #include <sys/share.h>
63 #include <vm/as.h>
64 #include <vm/seg.h>
65 #include <vm/seg_vn.h>
66 #include <util/qsort.h>
67 #include <sys/zone.h>
70 * utssys()
72 static int uts_fusers(char *, int, intptr_t);
73 static int _statvfs64_by_dev(dev_t, struct statvfs64 *);
75 #if defined(_ILP32) || defined(_SYSCALL32_IMPL)
77 static int utssys_ustat32(dev_t, struct ustat32 *);
79 int64_t
80 utssys32(void *buf, int arg, int type, void *outbp)
82 int error;
83 rval_t rv;
85 rv.r_vals = 0;
87 switch (type) {
88 case UTS_USTAT:
89 error = utssys_ustat32(expldev((dev32_t)arg), buf);
90 break;
91 case UTS_FUSERS:
92 error = uts_fusers(buf, arg, (intptr_t)outbp);
93 break;
94 default:
95 error = EINVAL;
96 break;
99 return (error == 0 ? rv.r_vals : (int64_t)set_errno(error));
102 static int
103 utssys_ustat32(dev_t dev, struct ustat32 *cbuf)
105 struct ustat32 ust32;
106 struct statvfs64 stvfs;
107 fsblkcnt64_t fsbc64;
108 char *cp, *cp2;
109 int i, error;
111 if ((error = _statvfs64_by_dev(dev, &stvfs)) != 0)
112 return (error);
114 fsbc64 = stvfs.f_bfree * (stvfs.f_frsize / 512);
116 * Check to see if the number of free blocks can be expressed
117 * in 31 bits or whether the number of free files is more than
118 * can be expressed in 32 bits and is not -1 (UINT64_MAX). NFS
119 * Version 2 does not support the number of free files and
120 * hence will return -1. -1, when translated from a 32 bit
121 * quantity to an unsigned 64 bit quantity, turns into UINT64_MAX.
123 if (fsbc64 > INT32_MAX ||
124 (stvfs.f_ffree > UINT32_MAX && stvfs.f_ffree != UINT64_MAX))
125 return (EOVERFLOW);
127 ust32.f_tfree = (daddr32_t)fsbc64;
128 ust32.f_tinode = (ino32_t)stvfs.f_ffree;
130 cp = stvfs.f_fstr;
131 cp2 = ust32.f_fname;
132 i = 0;
133 while (i++ < sizeof (ust32.f_fname))
134 if (*cp != '\0')
135 *cp2++ = *cp++;
136 else
137 *cp2++ = '\0';
138 while (*cp != '\0' &&
139 (i++ < sizeof (stvfs.f_fstr) - sizeof (ust32.f_fpack)))
140 cp++;
141 (void) strncpy(ust32.f_fpack, cp + 1, sizeof (ust32.f_fpack));
143 if (copyout(&ust32, cbuf, sizeof (ust32)))
144 return (EFAULT);
145 return (0);
148 #endif /* _ILP32 || _SYSCALL32_IMPL */
150 #ifdef _LP64
152 static int uts_ustat64(dev_t, struct ustat *);
154 int64_t
155 utssys64(void *buf, long arg, int type, void *outbp)
157 int error;
158 rval_t rv;
160 rv.r_vals = 0;
162 switch (type) {
163 case UTS_USTAT:
164 error = uts_ustat64((dev_t)arg, buf);
165 break;
166 case UTS_FUSERS:
167 error = uts_fusers(buf, (int)arg, (intptr_t)outbp);
168 break;
169 default:
170 error = EINVAL;
171 break;
174 return (error == 0 ? rv.r_vals : (int64_t)set_errno(error));
177 static int
178 uts_ustat64(dev_t dev, struct ustat *cbuf)
180 struct ustat ust;
181 struct statvfs64 stvfs;
182 fsblkcnt64_t fsbc64;
183 char *cp, *cp2;
184 int i, error;
186 if ((error = _statvfs64_by_dev(dev, &stvfs)) != 0)
187 return (error);
189 fsbc64 = stvfs.f_bfree * (stvfs.f_frsize / 512);
190 ust.f_tfree = (daddr_t)fsbc64;
191 ust.f_tinode = (ino_t)stvfs.f_ffree;
193 cp = stvfs.f_fstr;
194 cp2 = ust.f_fname;
195 i = 0;
196 while (i++ < sizeof (ust.f_fname))
197 if (*cp != '\0')
198 *cp2++ = *cp++;
199 else
200 *cp2++ = '\0';
201 while (*cp != '\0' &&
202 (i++ < sizeof (stvfs.f_fstr) - sizeof (ust.f_fpack)))
203 cp++;
204 (void) strncpy(ust.f_fpack, cp + 1, sizeof (ust.f_fpack));
206 if (copyout(&ust, cbuf, sizeof (ust)))
207 return (EFAULT);
208 return (0);
211 #endif /* _LP64 */
214 * Utility routine for the ustat implementations.
215 * (If it wasn't for the 'find-by-dev_t' semantic of ustat(2), we could push
216 * this all out into userland, sigh.)
218 static int
219 _statvfs64_by_dev(dev_t dev, struct statvfs64 *svp)
221 vfs_t *vfsp;
222 int error;
224 if ((vfsp = vfs_dev2vfsp(dev)) == NULL) {
226 * See if it's the root of our zone.
228 vfsp = curproc->p_zone->zone_rootvp->v_vfsp;
229 if (vfsp->vfs_dev == dev) {
230 VFS_HOLD(vfsp);
231 } else {
232 vfsp = NULL;
235 if (vfsp == NULL)
236 return (EINVAL);
237 error = VFS_STATVFS(vfsp, svp);
238 VFS_RELE(vfsp);
239 return (error);
243 * Check if this pid has an NBMAND lock or share reservation
244 * on this vp. llp is a snapshoted list of all NBMAND locks
245 * set by this pid. Return 1 if there is an NBMAND lock else
246 * return 0.
248 static int
249 proc_has_nbmand_on_vp(vnode_t *vp, pid_t pid, locklist_t *llp)
252 * Any NBMAND lock held by the process on this vp?
254 while (llp) {
255 if (llp->ll_vp == vp) {
256 return (1);
258 llp = llp->ll_next;
261 * Any NBMAND share reservation on the vp for this process?
263 return (proc_has_nbmand_share_on_vp(vp, pid));
266 static fu_data_t *
267 dofusers(vnode_t *fvp, int flags)
269 fu_data_t *fu_data;
270 proc_t *prp;
271 vfs_t *cvfsp;
272 pid_t npids, pidx, *pidlist;
273 int v_proc = v.v_proc; /* max # of procs */
274 int pcnt = 0;
275 int contained = (flags & F_CONTAINED);
276 int nbmandonly = (flags & F_NBMANDLIST);
277 int dip_usage = (flags & F_DEVINFO);
278 int fvp_isdev = vn_matchops(fvp, spec_getvnodeops());
279 zone_t *zone = curproc->p_zone;
280 int inglobal = INGLOBALZONE(curproc);
282 /* get a pointer to the file system containing this vnode */
283 cvfsp = fvp->v_vfsp;
284 ASSERT(cvfsp);
286 /* allocate the data structure to return our results in */
287 fu_data = kmem_alloc(fu_data_size(v_proc), KM_SLEEP);
288 fu_data->fud_user_max = v_proc;
289 fu_data->fud_user_count = 0;
291 /* get a snapshot of all the pids we're going to check out */
292 pidlist = kmem_alloc(v_proc * sizeof (pid_t), KM_SLEEP);
293 mutex_enter(&pidlock);
294 for (npids = 0, prp = practive; prp != NULL; prp = prp->p_next) {
295 if (inglobal || prp->p_zone == zone)
296 pidlist[npids++] = prp->p_pid;
298 mutex_exit(&pidlock);
300 /* grab each process and check its file usage */
301 for (pidx = 0; pidx < npids; pidx++) {
302 locklist_t *llp = NULL;
303 uf_info_t *fip;
304 vnode_t *vp;
305 user_t *up;
306 sess_t *sp;
307 uid_t uid;
308 pid_t pid = pidlist[pidx];
309 int i, use_flag = 0;
312 * grab prp->p_lock using sprlock()
313 * if sprlock() fails the process does not exists anymore
315 prp = sprlock(pid);
316 if (prp == NULL)
317 continue;
319 /* get the processes credential info in case we need it */
320 mutex_enter(&prp->p_crlock);
321 uid = crgetruid(prp->p_cred);
322 mutex_exit(&prp->p_crlock);
325 * it's safe to drop p_lock here because we
326 * called sprlock() before and it set the SPRLOCK
327 * flag for the process so it won't go away.
329 mutex_exit(&prp->p_lock);
332 * now we want to walk a processes open file descriptors
333 * to do this we need to grab the fip->fi_lock. (you
334 * can't hold p_lock when grabbing the fip->fi_lock.)
336 fip = P_FINFO(prp);
337 mutex_enter(&fip->fi_lock);
340 * Snapshot nbmand locks for pid
342 llp = flk_active_nbmand_locks(prp->p_pid);
343 for (i = 0; i < fip->fi_nfiles; i++) {
344 uf_entry_t *ufp;
345 file_t *fp;
347 UF_ENTER(ufp, fip, i);
348 if (((fp = ufp->uf_file) == NULL) ||
349 ((vp = fp->f_vnode) == NULL)) {
350 UF_EXIT(ufp);
351 continue;
355 * if the target file (fvp) is not a device
356 * and corrosponds to the root of a filesystem
357 * (cvfsp), then check if it contains the file
358 * is use by this process (vp).
360 if (contained && (vp->v_vfsp == cvfsp))
361 use_flag |= F_OPEN;
364 * if the target file (fvp) is not a device,
365 * then check if it matches the file in use
366 * by this process (vp).
368 if (!fvp_isdev && VN_CMP(fvp, vp))
369 use_flag |= F_OPEN;
372 * if the target file (fvp) is a device,
373 * then check if the current file in use
374 * by this process (vp) maps to the same device
375 * minor node.
377 if (fvp_isdev &&
378 vn_matchops(vp, spec_getvnodeops()) &&
379 (fvp->v_rdev == vp->v_rdev))
380 use_flag |= F_OPEN;
383 * if the target file (fvp) is a device,
384 * and we're checking for device instance
385 * usage, then check if the current file in use
386 * by this process (vp) maps to the same device
387 * instance.
389 if (dip_usage &&
390 vn_matchops(vp, spec_getvnodeops()) &&
391 (VTOCS(fvp)->s_dip == VTOCS(vp)->s_dip))
392 use_flag |= F_OPEN;
395 * if the current file in use by this process (vp)
396 * doesn't match what we're looking for, move on
397 * to the next file in the process.
399 if ((use_flag & F_OPEN) == 0) {
400 UF_EXIT(ufp);
401 continue;
404 if (proc_has_nbmand_on_vp(vp, prp->p_pid, llp)) {
405 /* A nbmand found so we're done. */
406 use_flag |= F_NBM;
407 UF_EXIT(ufp);
408 break;
410 UF_EXIT(ufp);
412 if (llp)
413 flk_free_locklist(llp);
415 mutex_exit(&fip->fi_lock);
418 * If nbmand usage tracking is desired and no nbmand was
419 * found for this process, then no need to do further
420 * usage tracking for this process.
422 if (nbmandonly && (!(use_flag & F_NBM))) {
424 * grab the process lock again, clear the SPRLOCK
425 * flag, release the process, and continue.
427 mutex_enter(&prp->p_lock);
428 sprunlock(prp);
429 continue;
433 * All other types of usage.
434 * For the next few checks we need to hold p_lock.
436 mutex_enter(&prp->p_lock);
437 up = PTOU(prp);
438 if (fvp_isdev) {
440 * if the target file (fvp) is a device
441 * then check if it matches the processes tty
443 * we grab s_lock to protect ourselves against
444 * freectty() freeing the vnode out from under us.
446 sp = prp->p_sessp;
447 mutex_enter(&sp->s_lock);
448 vp = prp->p_sessp->s_vp;
449 if (vp != NULL) {
450 if (fvp->v_rdev == vp->v_rdev)
451 use_flag |= F_TTY;
453 if (dip_usage &&
454 (VTOCS(fvp)->s_dip == VTOCS(vp)->s_dip))
455 use_flag |= F_TTY;
457 mutex_exit(&sp->s_lock);
458 } else {
459 /* check the processes current working directory */
460 if (up->u_cdir &&
461 (VN_CMP(fvp, up->u_cdir) ||
462 (contained && (up->u_cdir->v_vfsp == cvfsp))))
463 use_flag |= F_CDIR;
465 /* check the processes root directory */
466 if (up->u_rdir &&
467 (VN_CMP(fvp, up->u_rdir) ||
468 (contained && (up->u_rdir->v_vfsp == cvfsp))))
469 use_flag |= F_RDIR;
471 /* check the program text vnode */
472 if (prp->p_exec &&
473 (VN_CMP(fvp, prp->p_exec) ||
474 (contained && (prp->p_exec->v_vfsp == cvfsp))))
475 use_flag |= F_TEXT;
478 /* Now we can drop p_lock again */
479 mutex_exit(&prp->p_lock);
482 * now we want to walk a processes memory mappings.
483 * to do this we need to grab the prp->p_as lock. (you
484 * can't hold p_lock when grabbing the prp->p_as lock.)
486 if (prp->p_as != &kas) {
487 struct seg *seg;
488 struct as *as = prp->p_as;
490 AS_LOCK_ENTER(as, RW_READER);
491 for (seg = AS_SEGFIRST(as); seg;
492 seg = AS_SEGNEXT(as, seg)) {
494 * if we can't get a backing vnode for this
495 * segment then skip it
497 vp = NULL;
498 if ((segop_getvp(seg, seg->s_base, &vp)) ||
499 (vp == NULL))
500 continue;
503 * if the target file (fvp) is not a device
504 * and corrosponds to the root of a filesystem
505 * (cvfsp), then check if it contains the
506 * vnode backing this segment (vp).
508 if (contained && (vp->v_vfsp == cvfsp)) {
509 use_flag |= F_MAP;
510 break;
514 * if the target file (fvp) is not a device,
515 * check if it matches the the vnode backing
516 * this segment (vp).
518 if (!fvp_isdev && VN_CMP(fvp, vp)) {
519 use_flag |= F_MAP;
520 break;
524 * if the target file (fvp) isn't a device,
525 * or the the vnode backing this segment (vp)
526 * isn't a device then continue.
528 if (!fvp_isdev ||
529 !vn_matchops(vp, spec_getvnodeops()))
530 continue;
533 * check if the vnode backing this segment
534 * (vp) maps to the same device minor node
535 * as the target device (fvp)
537 if (fvp->v_rdev == vp->v_rdev) {
538 use_flag |= F_MAP;
539 break;
543 * if we're checking for device instance
544 * usage, then check if the vnode backing
545 * this segment (vp) maps to the same device
546 * instance as the target device (fvp).
548 if (dip_usage &&
549 (VTOCS(fvp)->s_dip == VTOCS(vp)->s_dip)) {
550 use_flag |= F_MAP;
551 break;
554 AS_LOCK_EXIT(as);
557 if (use_flag) {
558 ASSERT(pcnt < fu_data->fud_user_max);
559 fu_data->fud_user[pcnt].fu_flags = use_flag;
560 fu_data->fud_user[pcnt].fu_pid = pid;
561 fu_data->fud_user[pcnt].fu_uid = uid;
562 pcnt++;
566 * grab the process lock again, clear the SPRLOCK
567 * flag, release the process, and continue.
569 mutex_enter(&prp->p_lock);
570 sprunlock(prp);
573 kmem_free(pidlist, v_proc * sizeof (pid_t));
575 fu_data->fud_user_count = pcnt;
576 return (fu_data);
579 typedef struct dofkusers_arg {
580 vnode_t *fvp;
581 int flags;
582 int *error;
583 fu_data_t *fu_data;
584 } dofkusers_arg_t;
586 static int
587 dofkusers_walker(const ldi_usage_t *ldi_usage, void *arg)
589 dofkusers_arg_t *dofkusers_arg = (dofkusers_arg_t *)arg;
591 vnode_t *fvp = dofkusers_arg->fvp;
592 int flags = dofkusers_arg->flags;
593 int *error = dofkusers_arg->error;
594 fu_data_t *fu_data = dofkusers_arg->fu_data;
596 modid_t modid;
597 minor_t minor;
598 int instance;
599 int dip_usage = (flags & F_DEVINFO);
601 ASSERT(*error == 0);
602 ASSERT(vn_matchops(fvp, spec_getvnodeops()));
605 * check if the dev_t of the target device matches the dev_t
606 * of the device we're trying to find usage info for.
608 if (fvp->v_rdev != ldi_usage->tgt_devt) {
611 * if the dev_ts don't match and we're not trying
612 * to find usage information for device instances
613 * then return
615 if (!dip_usage)
616 return (LDI_USAGE_CONTINUE);
620 * we're trying to find usage information for an
621 * device instance instead of just a minor node.
623 * check if the dip for the target device matches the
624 * dip of the device we're trying to find usage info for.
626 if (VTOCS(fvp)->s_dip != ldi_usage->tgt_dip)
627 return (LDI_USAGE_CONTINUE);
630 if (fu_data->fud_user_count >= fu_data->fud_user_max) {
631 *error = E2BIG;
632 return (LDI_USAGE_TERMINATE);
635 /* get the device vnode user information */
636 modid = ldi_usage->src_modid;
637 ASSERT(modid != -1);
639 minor = instance = -1;
640 if (ldi_usage->src_dip != NULL) {
641 instance = DEVI(ldi_usage->src_dip)->devi_instance;
643 if (ldi_usage->src_devt != DDI_DEV_T_NONE) {
644 minor = getminor(ldi_usage->src_devt);
647 /* set the device vnode user information */
648 fu_data->fud_user[fu_data->fud_user_count].fu_flags = F_KERNEL;
649 fu_data->fud_user[fu_data->fud_user_count].fu_modid = modid;
650 fu_data->fud_user[fu_data->fud_user_count].fu_instance = instance;
651 fu_data->fud_user[fu_data->fud_user_count].fu_minor = minor;
653 fu_data->fud_user_count++;
655 return (LDI_USAGE_CONTINUE);
659 f_user_cmp(const void *arg1, const void *arg2)
661 f_user_t *f_user1 = (f_user_t *)arg1;
662 f_user_t *f_user2 = (f_user_t *)arg2;
665 * we should only be called for f_user_t entires that represent
666 * a kernel file consumer
668 ASSERT(f_user1->fu_flags & F_KERNEL);
669 ASSERT(f_user2->fu_flags & F_KERNEL);
671 if (f_user1->fu_modid != f_user2->fu_modid)
672 return ((f_user1->fu_modid < f_user2->fu_modid) ? -1 : 1);
674 if (f_user1->fu_instance != f_user2->fu_instance)
675 return ((f_user1->fu_instance < f_user2->fu_instance) ? -1 : 1);
677 if (f_user1->fu_minor != f_user2->fu_minor)
678 return ((f_user1->fu_minor < f_user2->fu_minor) ? -1 : 1);
680 return (0);
683 static fu_data_t *
684 dofkusers(vnode_t *fvp, int flags, int *error)
686 dofkusers_arg_t dofkusers_arg;
687 fu_data_t *fu_data;
688 int user_max, i;
691 * we only keep track of kernel device consumers, so if the
692 * target vnode isn't a device then there's nothing to do here
694 if (!vn_matchops(fvp, spec_getvnodeops()))
695 return (NULL);
697 /* allocate the data structure to return our results in */
698 user_max = ldi_usage_count();
699 fu_data = kmem_alloc(fu_data_size(user_max), KM_SLEEP);
700 fu_data->fud_user_max = user_max;
701 fu_data->fud_user_count = 0;
703 /* invoke the callback to collect device usage information */
704 dofkusers_arg.fvp = fvp;
705 dofkusers_arg.flags = flags;
706 dofkusers_arg.error = error;
707 dofkusers_arg.fu_data = fu_data;
708 ldi_usage_walker(&dofkusers_arg, dofkusers_walker);
710 /* check for errors */
711 if (*error != 0)
712 return (fu_data);
714 /* if there aren't any file consumers then return */
715 if (fu_data->fud_user_count == 0)
716 return (fu_data);
719 * since we ignore the spec_type of the target we're trying to
720 * access it's possible that we could have duplicates entries in
721 * the list of consumers.
723 * we don't want to check for duplicate in the callback because
724 * we're holding locks in the ldi when the callback is invoked.
726 * so here we need to go through the array of file consumers
727 * and remove duplicate entries.
730 /* first sort the array of file consumers */
731 qsort((caddr_t)fu_data->fud_user, fu_data->fud_user_count,
732 sizeof (f_user_t), f_user_cmp);
734 /* then remove any duplicate entires */
735 i = 1;
736 while (i < fu_data->fud_user_count) {
738 if (f_user_cmp(&fu_data->fud_user[i],
739 &fu_data->fud_user[i - 1]) != 0) {
741 * the current element is unique, move onto
742 * the next one
744 i++;
745 continue;
749 * this entry is a duplicate so if it's not the last
750 * entry in the array then remove it.
752 fu_data->fud_user_count--;
753 if (i == fu_data->fud_user_count)
754 break;
756 bcopy(&fu_data->fud_user[i + 1], &fu_data->fud_user[i],
757 sizeof (f_user_t) * (fu_data->fud_user_count - i));
760 return (fu_data);
764 * Determine the ways in which processes and the kernel are using a named
765 * file or mounted file system (path). Normally return 0. In case of an
766 * error appropriate errno will be returned.
768 * Upon success, uts_fusers will also copyout the file usage information
769 * in the form of an array of f_user_t's that are contained within an
770 * fu_data_t pointed to by userbp.
772 static int
773 uts_fusers(char *path, int flags, intptr_t userbp)
775 fu_data_t *fu_data = NULL, *fuk_data = NULL;
776 fu_data_t fu_header;
777 vnode_t *fvp = NULL;
778 size_t bcount;
779 int error = 0;
780 int total_max, total_out;
781 int contained = (flags & F_CONTAINED);
782 int dip_usage = (flags & F_DEVINFO);
783 int fvp_isdev;
786 /* figure out how man f_user_t's we can safetly copy out */
787 if (copyin((const void *)userbp, &total_max, sizeof (total_max)))
788 return (EFAULT);
791 * check if we only want a count of how many kernel device
792 * consumers exist
794 if (flags & F_KINFO_COUNT) {
795 fu_header.fud_user_max = total_max;
796 fu_header.fud_user_count = ldi_usage_count();
797 bcount = fu_data_size(0);
798 if (copyout(&fu_header, (void *)userbp, bcount))
799 return (EFAULT);
800 return (0);
803 /* get the vnode for the file we want to look up usage for */
804 error = lookupname(path, UIO_USERSPACE, FOLLOW, NULLVPP, &fvp);
805 if (error != 0)
806 return (error);
807 ASSERT(fvp);
808 fvp_isdev = vn_matchops(fvp, spec_getvnodeops());
811 * if we want to report usage for all files contained within a
812 * file system then the target file better correspond to the
813 * root node of a mounted file system, or the root of a zone.
815 if (contained && !(fvp->v_flag & VROOT) &&
816 fvp != curproc->p_zone->zone_rootvp) {
817 error = EINVAL;
818 goto out;
822 * if we want to report usage for all files contained within a
823 * file system then the target file better not be a device.
825 if (contained && fvp_isdev) {
826 error = EINVAL;
827 goto out;
831 * if we want to report usage for a device instance then the
832 * target file better corrospond to a device
834 if (dip_usage && !fvp_isdev) {
835 error = EINVAL;
836 goto out;
840 * if the target vnode isn't a device and it has a reference count
841 * of one then no one else is going to have it open so we don't
842 * have any work to do.
844 if (!fvp_isdev && (fvp->v_count == 1)) {
845 goto out;
848 /* look up usage information for this vnode */
849 fu_data = dofusers(fvp, flags);
850 fuk_data = dofkusers(fvp, flags, &error);
851 if (error != 0)
852 goto out;
854 /* get a count of the number of f_user_t's we need to copy out */
855 total_out = 0;
856 if (fu_data)
857 total_out += fu_data->fud_user_count;
858 if (fuk_data)
859 total_out += fuk_data->fud_user_count;
861 /* check if there is enough space to copyout all results */
862 if (total_out > total_max) {
863 error = E2BIG;
864 goto out;
867 /* copyout file usage info counts */
868 fu_header.fud_user_max = total_max;
869 fu_header.fud_user_count = total_out;
870 bcount = fu_data_size(0);
871 if (copyout(&fu_header, (void *)userbp, bcount)) {
872 error = EFAULT;
873 goto out;
876 /* copyout userland process file usage info */
877 if ((fu_data != NULL) && (fu_data->fud_user_count > 0)) {
878 userbp += bcount;
879 bcount = fu_data->fud_user_count * sizeof (f_user_t);
880 if (copyout(fu_data->fud_user, (void *)userbp, bcount)) {
881 error = EFAULT;
882 goto out;
886 /* copyout kernel file usage info */
887 if ((fuk_data != NULL) && (fuk_data->fud_user_count > 0)) {
888 userbp += bcount;
889 bcount = fuk_data->fud_user_count * sizeof (f_user_t);
890 if (copyout(fuk_data->fud_user, (void *)userbp, bcount)) {
891 error = EFAULT;
892 goto out;
896 out:
897 /* release the vnode that we were looking up usage for */
898 VN_RELE(fvp);
900 /* release any allocated memory */
901 if (fu_data)
902 kmem_free(fu_data, fu_data_size(fu_data->fud_user_max));
903 if (fuk_data)
904 kmem_free(fuk_data, fu_data_size(fuk_data->fud_user_max));
906 return (error);