Print this page
patch lower-case-segops
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/syscall/utssys.c
+++ new/usr/src/uts/common/syscall/utssys.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License, Version 1.0 only
6 6 * (the "License"). You may not use this file except in compliance
7 7 * with the License.
8 8 *
9 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 10 * or http://www.opensolaris.org/os/licensing.
11 11 * See the License for the specific language governing permissions
12 12 * and limitations under the License.
13 13 *
14 14 * When distributing Covered Code, include this CDDL HEADER in each
15 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 16 * If applicable, add the following below this CDDL HEADER, with the
17 17 * fields enclosed by brackets "[]" replaced with your own identifying
18 18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 19 *
20 20 * CDDL HEADER END
21 21 */
↓ open down ↓ |
21 lines elided |
↑ open up ↑ |
22 22
23 23 /*
24 24 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
25 25 * Use is subject to license terms.
26 26 */
27 27
28 28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
29 29 /* All Rights Reserved */
30 30
31 31
32 -#pragma ident "%Z%%M% %I% %E% SMI"
33 -
34 32 #include <sys/param.h>
35 33 #include <sys/inttypes.h>
36 34 #include <sys/types.h>
37 35 #include <sys/sysmacros.h>
38 36 #include <sys/systm.h>
39 37 #include <sys/user.h>
40 38 #include <sys/errno.h>
41 39 #include <sys/vfs.h>
42 40 #include <sys/vnode.h>
43 41 #include <sys/file.h>
44 42 #include <sys/proc.h>
45 43 #include <sys/session.h>
46 44 #include <sys/var.h>
47 45 #include <sys/utsname.h>
48 46 #include <sys/utssys.h>
49 47 #include <sys/ustat.h>
50 48 #include <sys/statvfs.h>
51 49 #include <sys/kmem.h>
52 50 #include <sys/debug.h>
53 51 #include <sys/pathname.h>
54 52 #include <sys/modctl.h>
55 53 #include <sys/fs/snode.h>
56 54 #include <sys/sunldi_impl.h>
57 55 #include <sys/ddi.h>
58 56 #include <sys/sunddi.h>
59 57 #include <sys/cmn_err.h>
60 58 #include <sys/ddipropdefs.h>
61 59 #include <sys/ddi_impldefs.h>
62 60 #include <sys/modctl.h>
63 61 #include <sys/flock.h>
64 62 #include <sys/share.h>
65 63 #include <vm/as.h>
66 64 #include <vm/seg.h>
67 65 #include <vm/seg_vn.h>
68 66 #include <util/qsort.h>
69 67 #include <sys/zone.h>
70 68
71 69 /*
72 70 * utssys()
73 71 */
74 72 static int uts_fusers(char *, int, intptr_t);
75 73 static int _statvfs64_by_dev(dev_t, struct statvfs64 *);
76 74
77 75 #if defined(_ILP32) || defined(_SYSCALL32_IMPL)
78 76
79 77 static int utssys_uname32(caddr_t, rval_t *);
80 78 static int utssys_ustat32(dev_t, struct ustat32 *);
81 79
82 80 int64_t
83 81 utssys32(void *buf, int arg, int type, void *outbp)
84 82 {
85 83 int error;
86 84 rval_t rv;
87 85
88 86 rv.r_vals = 0;
89 87
90 88 switch (type) {
91 89 case UTS_UNAME:
92 90 /*
93 91 * This is an obsolete way to get the utsname structure
94 92 * (it only gives you the first 8 characters of each field!)
95 93 * uname(2) is the preferred and better interface.
96 94 */
97 95 error = utssys_uname32(buf, &rv);
98 96 break;
99 97 case UTS_USTAT:
100 98 error = utssys_ustat32(expldev((dev32_t)arg), buf);
101 99 break;
102 100 case UTS_FUSERS:
103 101 error = uts_fusers(buf, arg, (intptr_t)outbp);
104 102 break;
105 103 default:
106 104 error = EINVAL;
107 105 break;
108 106 }
109 107
110 108 return (error == 0 ? rv.r_vals : (int64_t)set_errno(error));
111 109 }
112 110
113 111 static int
114 112 utssys_uname32(caddr_t buf, rval_t *rvp)
115 113 {
116 114 if (copyout(utsname.sysname, buf, 8))
117 115 return (EFAULT);
118 116 buf += 8;
119 117 if (subyte(buf, 0) < 0)
120 118 return (EFAULT);
121 119 buf++;
122 120 if (copyout(uts_nodename(), buf, 8))
123 121 return (EFAULT);
124 122 buf += 8;
125 123 if (subyte(buf, 0) < 0)
126 124 return (EFAULT);
127 125 buf++;
128 126 if (copyout(utsname.release, buf, 8))
129 127 return (EFAULT);
130 128 buf += 8;
131 129 if (subyte(buf, 0) < 0)
132 130 return (EFAULT);
133 131 buf++;
134 132 if (copyout(utsname.version, buf, 8))
135 133 return (EFAULT);
136 134 buf += 8;
137 135 if (subyte(buf, 0) < 0)
138 136 return (EFAULT);
139 137 buf++;
140 138 if (copyout(utsname.machine, buf, 8))
141 139 return (EFAULT);
142 140 buf += 8;
143 141 if (subyte(buf, 0) < 0)
144 142 return (EFAULT);
145 143 rvp->r_val1 = 1;
146 144 return (0);
147 145 }
148 146
149 147 static int
150 148 utssys_ustat32(dev_t dev, struct ustat32 *cbuf)
151 149 {
152 150 struct ustat32 ust32;
153 151 struct statvfs64 stvfs;
154 152 fsblkcnt64_t fsbc64;
155 153 char *cp, *cp2;
156 154 int i, error;
157 155
158 156 if ((error = _statvfs64_by_dev(dev, &stvfs)) != 0)
159 157 return (error);
160 158
161 159 fsbc64 = stvfs.f_bfree * (stvfs.f_frsize / 512);
162 160 /*
163 161 * Check to see if the number of free blocks can be expressed
164 162 * in 31 bits or whether the number of free files is more than
165 163 * can be expressed in 32 bits and is not -1 (UINT64_MAX). NFS
166 164 * Version 2 does not support the number of free files and
167 165 * hence will return -1. -1, when translated from a 32 bit
168 166 * quantity to an unsigned 64 bit quantity, turns into UINT64_MAX.
169 167 */
170 168 if (fsbc64 > INT32_MAX ||
171 169 (stvfs.f_ffree > UINT32_MAX && stvfs.f_ffree != UINT64_MAX))
172 170 return (EOVERFLOW);
173 171
174 172 ust32.f_tfree = (daddr32_t)fsbc64;
175 173 ust32.f_tinode = (ino32_t)stvfs.f_ffree;
176 174
177 175 cp = stvfs.f_fstr;
178 176 cp2 = ust32.f_fname;
179 177 i = 0;
180 178 while (i++ < sizeof (ust32.f_fname))
181 179 if (*cp != '\0')
182 180 *cp2++ = *cp++;
183 181 else
184 182 *cp2++ = '\0';
185 183 while (*cp != '\0' &&
186 184 (i++ < sizeof (stvfs.f_fstr) - sizeof (ust32.f_fpack)))
187 185 cp++;
188 186 (void) strncpy(ust32.f_fpack, cp + 1, sizeof (ust32.f_fpack));
189 187
190 188 if (copyout(&ust32, cbuf, sizeof (ust32)))
191 189 return (EFAULT);
192 190 return (0);
193 191 }
194 192
195 193 #endif /* _ILP32 || _SYSCALL32_IMPL */
196 194
197 195 #ifdef _LP64
198 196
199 197 static int uts_ustat64(dev_t, struct ustat *);
200 198
201 199 int64_t
202 200 utssys64(void *buf, long arg, int type, void *outbp)
203 201 {
204 202 int error;
205 203 rval_t rv;
206 204
207 205 rv.r_vals = 0;
208 206
209 207 switch (type) {
210 208 case UTS_USTAT:
211 209 error = uts_ustat64((dev_t)arg, buf);
212 210 break;
213 211 case UTS_FUSERS:
214 212 error = uts_fusers(buf, (int)arg, (intptr_t)outbp);
215 213 break;
216 214 default:
217 215 error = EINVAL;
218 216 break;
219 217 }
220 218
221 219 return (error == 0 ? rv.r_vals : (int64_t)set_errno(error));
222 220 }
223 221
224 222 static int
225 223 uts_ustat64(dev_t dev, struct ustat *cbuf)
226 224 {
227 225 struct ustat ust;
228 226 struct statvfs64 stvfs;
229 227 fsblkcnt64_t fsbc64;
230 228 char *cp, *cp2;
231 229 int i, error;
232 230
233 231 if ((error = _statvfs64_by_dev(dev, &stvfs)) != 0)
234 232 return (error);
235 233
236 234 fsbc64 = stvfs.f_bfree * (stvfs.f_frsize / 512);
237 235 ust.f_tfree = (daddr_t)fsbc64;
238 236 ust.f_tinode = (ino_t)stvfs.f_ffree;
239 237
240 238 cp = stvfs.f_fstr;
241 239 cp2 = ust.f_fname;
242 240 i = 0;
243 241 while (i++ < sizeof (ust.f_fname))
244 242 if (*cp != '\0')
245 243 *cp2++ = *cp++;
246 244 else
247 245 *cp2++ = '\0';
248 246 while (*cp != '\0' &&
249 247 (i++ < sizeof (stvfs.f_fstr) - sizeof (ust.f_fpack)))
250 248 cp++;
251 249 (void) strncpy(ust.f_fpack, cp + 1, sizeof (ust.f_fpack));
252 250
253 251 if (copyout(&ust, cbuf, sizeof (ust)))
254 252 return (EFAULT);
255 253 return (0);
256 254 }
257 255
258 256 #endif /* _LP64 */
259 257
260 258 /*
261 259 * Utility routine for the ustat implementations.
262 260 * (If it wasn't for the 'find-by-dev_t' semantic of ustat(2), we could push
263 261 * this all out into userland, sigh.)
264 262 */
265 263 static int
266 264 _statvfs64_by_dev(dev_t dev, struct statvfs64 *svp)
267 265 {
268 266 vfs_t *vfsp;
269 267 int error;
270 268
271 269 if ((vfsp = vfs_dev2vfsp(dev)) == NULL) {
272 270 /*
273 271 * See if it's the root of our zone.
274 272 */
275 273 vfsp = curproc->p_zone->zone_rootvp->v_vfsp;
276 274 if (vfsp->vfs_dev == dev) {
277 275 VFS_HOLD(vfsp);
278 276 } else {
279 277 vfsp = NULL;
280 278 }
281 279 }
282 280 if (vfsp == NULL)
283 281 return (EINVAL);
284 282 error = VFS_STATVFS(vfsp, svp);
285 283 VFS_RELE(vfsp);
286 284 return (error);
287 285 }
288 286
289 287 /*
290 288 * Check if this pid has an NBMAND lock or share reservation
291 289 * on this vp. llp is a snapshoted list of all NBMAND locks
292 290 * set by this pid. Return 1 if there is an NBMAND lock else
293 291 * return 0.
294 292 */
295 293 static int
296 294 proc_has_nbmand_on_vp(vnode_t *vp, pid_t pid, locklist_t *llp)
297 295 {
298 296 /*
299 297 * Any NBMAND lock held by the process on this vp?
300 298 */
301 299 while (llp) {
302 300 if (llp->ll_vp == vp) {
303 301 return (1);
304 302 }
305 303 llp = llp->ll_next;
306 304 }
307 305 /*
308 306 * Any NBMAND share reservation on the vp for this process?
309 307 */
310 308 return (proc_has_nbmand_share_on_vp(vp, pid));
311 309 }
312 310
313 311 static fu_data_t *
314 312 dofusers(vnode_t *fvp, int flags)
315 313 {
316 314 fu_data_t *fu_data;
317 315 proc_t *prp;
318 316 vfs_t *cvfsp;
319 317 pid_t npids, pidx, *pidlist;
320 318 int v_proc = v.v_proc; /* max # of procs */
321 319 int pcnt = 0;
322 320 int contained = (flags & F_CONTAINED);
323 321 int nbmandonly = (flags & F_NBMANDLIST);
324 322 int dip_usage = (flags & F_DEVINFO);
325 323 int fvp_isdev = vn_matchops(fvp, spec_getvnodeops());
326 324 zone_t *zone = curproc->p_zone;
327 325 int inglobal = INGLOBALZONE(curproc);
328 326
329 327 /* get a pointer to the file system containing this vnode */
330 328 cvfsp = fvp->v_vfsp;
331 329 ASSERT(cvfsp);
332 330
333 331 /* allocate the data structure to return our results in */
334 332 fu_data = kmem_alloc(fu_data_size(v_proc), KM_SLEEP);
335 333 fu_data->fud_user_max = v_proc;
336 334 fu_data->fud_user_count = 0;
337 335
338 336 /* get a snapshot of all the pids we're going to check out */
339 337 pidlist = kmem_alloc(v_proc * sizeof (pid_t), KM_SLEEP);
340 338 mutex_enter(&pidlock);
341 339 for (npids = 0, prp = practive; prp != NULL; prp = prp->p_next) {
342 340 if (inglobal || prp->p_zone == zone)
343 341 pidlist[npids++] = prp->p_pid;
344 342 }
345 343 mutex_exit(&pidlock);
346 344
347 345 /* grab each process and check its file usage */
348 346 for (pidx = 0; pidx < npids; pidx++) {
349 347 locklist_t *llp = NULL;
350 348 uf_info_t *fip;
351 349 vnode_t *vp;
352 350 user_t *up;
353 351 sess_t *sp;
354 352 uid_t uid;
355 353 pid_t pid = pidlist[pidx];
356 354 int i, use_flag = 0;
357 355
358 356 /*
359 357 * grab prp->p_lock using sprlock()
360 358 * if sprlock() fails the process does not exists anymore
361 359 */
362 360 prp = sprlock(pid);
363 361 if (prp == NULL)
364 362 continue;
365 363
366 364 /* get the processes credential info in case we need it */
367 365 mutex_enter(&prp->p_crlock);
368 366 uid = crgetruid(prp->p_cred);
369 367 mutex_exit(&prp->p_crlock);
370 368
371 369 /*
372 370 * it's safe to drop p_lock here because we
373 371 * called sprlock() before and it set the SPRLOCK
374 372 * flag for the process so it won't go away.
375 373 */
376 374 mutex_exit(&prp->p_lock);
377 375
378 376 /*
379 377 * now we want to walk a processes open file descriptors
380 378 * to do this we need to grab the fip->fi_lock. (you
381 379 * can't hold p_lock when grabbing the fip->fi_lock.)
382 380 */
383 381 fip = P_FINFO(prp);
384 382 mutex_enter(&fip->fi_lock);
385 383
386 384 /*
387 385 * Snapshot nbmand locks for pid
388 386 */
389 387 llp = flk_active_nbmand_locks(prp->p_pid);
390 388 for (i = 0; i < fip->fi_nfiles; i++) {
391 389 uf_entry_t *ufp;
392 390 file_t *fp;
393 391
394 392 UF_ENTER(ufp, fip, i);
395 393 if (((fp = ufp->uf_file) == NULL) ||
396 394 ((vp = fp->f_vnode) == NULL)) {
397 395 UF_EXIT(ufp);
398 396 continue;
399 397 }
400 398
401 399 /*
402 400 * if the target file (fvp) is not a device
403 401 * and corrosponds to the root of a filesystem
404 402 * (cvfsp), then check if it contains the file
405 403 * is use by this process (vp).
406 404 */
407 405 if (contained && (vp->v_vfsp == cvfsp))
408 406 use_flag |= F_OPEN;
409 407
410 408 /*
411 409 * if the target file (fvp) is not a device,
412 410 * then check if it matches the file in use
413 411 * by this process (vp).
414 412 */
415 413 if (!fvp_isdev && VN_CMP(fvp, vp))
416 414 use_flag |= F_OPEN;
417 415
418 416 /*
419 417 * if the target file (fvp) is a device,
420 418 * then check if the current file in use
421 419 * by this process (vp) maps to the same device
422 420 * minor node.
423 421 */
424 422 if (fvp_isdev &&
425 423 vn_matchops(vp, spec_getvnodeops()) &&
426 424 (fvp->v_rdev == vp->v_rdev))
427 425 use_flag |= F_OPEN;
428 426
429 427 /*
430 428 * if the target file (fvp) is a device,
431 429 * and we're checking for device instance
432 430 * usage, then check if the current file in use
433 431 * by this process (vp) maps to the same device
434 432 * instance.
435 433 */
436 434 if (dip_usage &&
437 435 vn_matchops(vp, spec_getvnodeops()) &&
438 436 (VTOCS(fvp)->s_dip == VTOCS(vp)->s_dip))
439 437 use_flag |= F_OPEN;
440 438
441 439 /*
442 440 * if the current file in use by this process (vp)
443 441 * doesn't match what we're looking for, move on
444 442 * to the next file in the process.
445 443 */
446 444 if ((use_flag & F_OPEN) == 0) {
447 445 UF_EXIT(ufp);
448 446 continue;
449 447 }
450 448
451 449 if (proc_has_nbmand_on_vp(vp, prp->p_pid, llp)) {
452 450 /* A nbmand found so we're done. */
453 451 use_flag |= F_NBM;
454 452 UF_EXIT(ufp);
455 453 break;
456 454 }
457 455 UF_EXIT(ufp);
458 456 }
459 457 if (llp)
460 458 flk_free_locklist(llp);
461 459
462 460 mutex_exit(&fip->fi_lock);
463 461
464 462 /*
465 463 * If nbmand usage tracking is desired and no nbmand was
466 464 * found for this process, then no need to do further
467 465 * usage tracking for this process.
468 466 */
469 467 if (nbmandonly && (!(use_flag & F_NBM))) {
470 468 /*
471 469 * grab the process lock again, clear the SPRLOCK
472 470 * flag, release the process, and continue.
473 471 */
474 472 mutex_enter(&prp->p_lock);
475 473 sprunlock(prp);
476 474 continue;
477 475 }
478 476
479 477 /*
480 478 * All other types of usage.
481 479 * For the next few checks we need to hold p_lock.
482 480 */
483 481 mutex_enter(&prp->p_lock);
484 482 up = PTOU(prp);
485 483 if (fvp_isdev) {
486 484 /*
487 485 * if the target file (fvp) is a device
488 486 * then check if it matches the processes tty
489 487 *
490 488 * we grab s_lock to protect ourselves against
491 489 * freectty() freeing the vnode out from under us.
492 490 */
493 491 sp = prp->p_sessp;
494 492 mutex_enter(&sp->s_lock);
495 493 vp = prp->p_sessp->s_vp;
496 494 if (vp != NULL) {
497 495 if (fvp->v_rdev == vp->v_rdev)
498 496 use_flag |= F_TTY;
499 497
500 498 if (dip_usage &&
501 499 (VTOCS(fvp)->s_dip == VTOCS(vp)->s_dip))
502 500 use_flag |= F_TTY;
503 501 }
504 502 mutex_exit(&sp->s_lock);
505 503 } else {
506 504 /* check the processes current working directory */
507 505 if (up->u_cdir &&
508 506 (VN_CMP(fvp, up->u_cdir) ||
509 507 (contained && (up->u_cdir->v_vfsp == cvfsp))))
510 508 use_flag |= F_CDIR;
511 509
512 510 /* check the processes root directory */
513 511 if (up->u_rdir &&
514 512 (VN_CMP(fvp, up->u_rdir) ||
515 513 (contained && (up->u_rdir->v_vfsp == cvfsp))))
516 514 use_flag |= F_RDIR;
517 515
518 516 /* check the program text vnode */
519 517 if (prp->p_exec &&
520 518 (VN_CMP(fvp, prp->p_exec) ||
521 519 (contained && (prp->p_exec->v_vfsp == cvfsp))))
522 520 use_flag |= F_TEXT;
523 521 }
524 522
525 523 /* Now we can drop p_lock again */
526 524 mutex_exit(&prp->p_lock);
527 525
528 526 /*
529 527 * now we want to walk a processes memory mappings.
530 528 * to do this we need to grab the prp->p_as lock. (you
531 529 * can't hold p_lock when grabbing the prp->p_as lock.)
532 530 */
533 531 if (prp->p_as != &kas) {
534 532 struct seg *seg;
↓ open down ↓ |
491 lines elided |
↑ open up ↑ |
535 533 struct as *as = prp->p_as;
536 534
537 535 AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
538 536 for (seg = AS_SEGFIRST(as); seg;
539 537 seg = AS_SEGNEXT(as, seg)) {
540 538 /*
541 539 * if we can't get a backing vnode for this
542 540 * segment then skip it
543 541 */
544 542 vp = NULL;
545 - if ((SEGOP_GETVP(seg, seg->s_base, &vp)) ||
543 + if ((segop_getvp(seg, seg->s_base, &vp)) ||
546 544 (vp == NULL))
547 545 continue;
548 546
549 547 /*
550 548 * if the target file (fvp) is not a device
551 549 * and corrosponds to the root of a filesystem
552 550 * (cvfsp), then check if it contains the
553 551 * vnode backing this segment (vp).
554 552 */
555 553 if (contained && (vp->v_vfsp == cvfsp)) {
556 554 use_flag |= F_MAP;
557 555 break;
558 556 }
559 557
560 558 /*
561 559 * if the target file (fvp) is not a device,
562 560 * check if it matches the the vnode backing
563 561 * this segment (vp).
564 562 */
565 563 if (!fvp_isdev && VN_CMP(fvp, vp)) {
566 564 use_flag |= F_MAP;
567 565 break;
568 566 }
569 567
570 568 /*
571 569 * if the target file (fvp) isn't a device,
572 570 * or the the vnode backing this segment (vp)
573 571 * isn't a device then continue.
574 572 */
575 573 if (!fvp_isdev ||
576 574 !vn_matchops(vp, spec_getvnodeops()))
577 575 continue;
578 576
579 577 /*
580 578 * check if the vnode backing this segment
581 579 * (vp) maps to the same device minor node
582 580 * as the target device (fvp)
583 581 */
584 582 if (fvp->v_rdev == vp->v_rdev) {
585 583 use_flag |= F_MAP;
586 584 break;
587 585 }
588 586
589 587 /*
590 588 * if we're checking for device instance
591 589 * usage, then check if the vnode backing
592 590 * this segment (vp) maps to the same device
593 591 * instance as the target device (fvp).
594 592 */
595 593 if (dip_usage &&
596 594 (VTOCS(fvp)->s_dip == VTOCS(vp)->s_dip)) {
597 595 use_flag |= F_MAP;
598 596 break;
599 597 }
600 598 }
601 599 AS_LOCK_EXIT(as, &as->a_lock);
602 600 }
603 601
604 602 if (use_flag) {
605 603 ASSERT(pcnt < fu_data->fud_user_max);
606 604 fu_data->fud_user[pcnt].fu_flags = use_flag;
607 605 fu_data->fud_user[pcnt].fu_pid = pid;
608 606 fu_data->fud_user[pcnt].fu_uid = uid;
609 607 pcnt++;
610 608 }
611 609
612 610 /*
613 611 * grab the process lock again, clear the SPRLOCK
614 612 * flag, release the process, and continue.
615 613 */
616 614 mutex_enter(&prp->p_lock);
617 615 sprunlock(prp);
618 616 }
619 617
620 618 kmem_free(pidlist, v_proc * sizeof (pid_t));
621 619
622 620 fu_data->fud_user_count = pcnt;
623 621 return (fu_data);
624 622 }
625 623
626 624 typedef struct dofkusers_arg {
627 625 vnode_t *fvp;
628 626 int flags;
629 627 int *error;
630 628 fu_data_t *fu_data;
631 629 } dofkusers_arg_t;
632 630
633 631 static int
634 632 dofkusers_walker(const ldi_usage_t *ldi_usage, void *arg)
635 633 {
636 634 dofkusers_arg_t *dofkusers_arg = (dofkusers_arg_t *)arg;
637 635
638 636 vnode_t *fvp = dofkusers_arg->fvp;
639 637 int flags = dofkusers_arg->flags;
640 638 int *error = dofkusers_arg->error;
641 639 fu_data_t *fu_data = dofkusers_arg->fu_data;
642 640
643 641 modid_t modid;
644 642 minor_t minor;
645 643 int instance;
646 644 int dip_usage = (flags & F_DEVINFO);
647 645
648 646 ASSERT(*error == 0);
649 647 ASSERT(vn_matchops(fvp, spec_getvnodeops()));
650 648
651 649 /*
652 650 * check if the dev_t of the target device matches the dev_t
653 651 * of the device we're trying to find usage info for.
654 652 */
655 653 if (fvp->v_rdev != ldi_usage->tgt_devt) {
656 654
657 655 /*
658 656 * if the dev_ts don't match and we're not trying
659 657 * to find usage information for device instances
660 658 * then return
661 659 */
662 660 if (!dip_usage)
663 661 return (LDI_USAGE_CONTINUE);
664 662
665 663
666 664 /*
667 665 * we're trying to find usage information for an
668 666 * device instance instead of just a minor node.
669 667 *
670 668 * check if the dip for the target device matches the
671 669 * dip of the device we're trying to find usage info for.
672 670 */
673 671 if (VTOCS(fvp)->s_dip != ldi_usage->tgt_dip)
674 672 return (LDI_USAGE_CONTINUE);
675 673 }
676 674
677 675 if (fu_data->fud_user_count >= fu_data->fud_user_max) {
678 676 *error = E2BIG;
679 677 return (LDI_USAGE_TERMINATE);
680 678 }
681 679
682 680 /* get the device vnode user information */
683 681 modid = ldi_usage->src_modid;
684 682 ASSERT(modid != -1);
685 683
686 684 minor = instance = -1;
687 685 if (ldi_usage->src_dip != NULL) {
688 686 instance = DEVI(ldi_usage->src_dip)->devi_instance;
689 687 }
690 688 if (ldi_usage->src_devt != DDI_DEV_T_NONE) {
691 689 minor = getminor(ldi_usage->src_devt);
692 690 }
693 691
694 692 /* set the device vnode user information */
695 693 fu_data->fud_user[fu_data->fud_user_count].fu_flags = F_KERNEL;
696 694 fu_data->fud_user[fu_data->fud_user_count].fu_modid = modid;
697 695 fu_data->fud_user[fu_data->fud_user_count].fu_instance = instance;
698 696 fu_data->fud_user[fu_data->fud_user_count].fu_minor = minor;
699 697
700 698 fu_data->fud_user_count++;
701 699
702 700 return (LDI_USAGE_CONTINUE);
703 701 }
704 702
705 703 int
706 704 f_user_cmp(const void *arg1, const void *arg2)
707 705 {
708 706 f_user_t *f_user1 = (f_user_t *)arg1;
709 707 f_user_t *f_user2 = (f_user_t *)arg2;
710 708
711 709 /*
712 710 * we should only be called for f_user_t entires that represent
713 711 * a kernel file consumer
714 712 */
715 713 ASSERT(f_user1->fu_flags & F_KERNEL);
716 714 ASSERT(f_user2->fu_flags & F_KERNEL);
717 715
718 716 if (f_user1->fu_modid != f_user2->fu_modid)
719 717 return ((f_user1->fu_modid < f_user2->fu_modid) ? -1 : 1);
720 718
721 719 if (f_user1->fu_instance != f_user2->fu_instance)
722 720 return ((f_user1->fu_instance < f_user2->fu_instance) ? -1 : 1);
723 721
724 722 if (f_user1->fu_minor != f_user2->fu_minor)
725 723 return ((f_user1->fu_minor < f_user2->fu_minor) ? -1 : 1);
726 724
727 725 return (0);
728 726 }
729 727
730 728 static fu_data_t *
731 729 dofkusers(vnode_t *fvp, int flags, int *error)
732 730 {
733 731 dofkusers_arg_t dofkusers_arg;
734 732 fu_data_t *fu_data;
735 733 int user_max, i;
736 734
737 735 /*
738 736 * we only keep track of kernel device consumers, so if the
739 737 * target vnode isn't a device then there's nothing to do here
740 738 */
741 739 if (!vn_matchops(fvp, spec_getvnodeops()))
742 740 return (NULL);
743 741
744 742 /* allocate the data structure to return our results in */
745 743 user_max = ldi_usage_count();
746 744 fu_data = kmem_alloc(fu_data_size(user_max), KM_SLEEP);
747 745 fu_data->fud_user_max = user_max;
748 746 fu_data->fud_user_count = 0;
749 747
750 748 /* invoke the callback to collect device usage information */
751 749 dofkusers_arg.fvp = fvp;
752 750 dofkusers_arg.flags = flags;
753 751 dofkusers_arg.error = error;
754 752 dofkusers_arg.fu_data = fu_data;
755 753 ldi_usage_walker(&dofkusers_arg, dofkusers_walker);
756 754
757 755 /* check for errors */
758 756 if (*error != 0)
759 757 return (fu_data);
760 758
761 759 /* if there aren't any file consumers then return */
762 760 if (fu_data->fud_user_count == 0)
763 761 return (fu_data);
764 762
765 763 /*
766 764 * since we ignore the spec_type of the target we're trying to
767 765 * access it's possible that we could have duplicates entries in
768 766 * the list of consumers.
769 767 *
770 768 * we don't want to check for duplicate in the callback because
771 769 * we're holding locks in the ldi when the callback is invoked.
772 770 *
773 771 * so here we need to go through the array of file consumers
774 772 * and remove duplicate entries.
775 773 */
776 774
777 775 /* first sort the array of file consumers */
778 776 qsort((caddr_t)fu_data->fud_user, fu_data->fud_user_count,
779 777 sizeof (f_user_t), f_user_cmp);
780 778
781 779 /* then remove any duplicate entires */
782 780 i = 1;
783 781 while (i < fu_data->fud_user_count) {
784 782
785 783 if (f_user_cmp(&fu_data->fud_user[i],
786 784 &fu_data->fud_user[i - 1]) != 0) {
787 785 /*
788 786 * the current element is unique, move onto
789 787 * the next one
790 788 */
791 789 i++;
792 790 continue;
793 791 }
794 792
795 793 /*
796 794 * this entry is a duplicate so if it's not the last
797 795 * entry in the array then remove it.
798 796 */
799 797 fu_data->fud_user_count--;
800 798 if (i == fu_data->fud_user_count)
801 799 break;
802 800
803 801 bcopy(&fu_data->fud_user[i + 1], &fu_data->fud_user[i],
804 802 sizeof (f_user_t) * (fu_data->fud_user_count - i));
805 803 }
806 804
807 805 return (fu_data);
808 806 }
809 807
810 808 /*
811 809 * Determine the ways in which processes and the kernel are using a named
812 810 * file or mounted file system (path). Normally return 0. In case of an
813 811 * error appropriate errno will be returned.
814 812 *
815 813 * Upon success, uts_fusers will also copyout the file usage information
816 814 * in the form of an array of f_user_t's that are contained within an
817 815 * fu_data_t pointed to by userbp.
818 816 */
819 817 static int
820 818 uts_fusers(char *path, int flags, intptr_t userbp)
821 819 {
822 820 fu_data_t *fu_data = NULL, *fuk_data = NULL;
823 821 fu_data_t fu_header;
824 822 vnode_t *fvp = NULL;
825 823 size_t bcount;
826 824 int error = 0;
827 825 int total_max, total_out;
828 826 int contained = (flags & F_CONTAINED);
829 827 int dip_usage = (flags & F_DEVINFO);
830 828 int fvp_isdev;
831 829
832 830
833 831 /* figure out how man f_user_t's we can safetly copy out */
834 832 if (copyin((const void *)userbp, &total_max, sizeof (total_max)))
835 833 return (EFAULT);
836 834
837 835 /*
838 836 * check if we only want a count of how many kernel device
839 837 * consumers exist
840 838 */
841 839 if (flags & F_KINFO_COUNT) {
842 840 fu_header.fud_user_max = total_max;
843 841 fu_header.fud_user_count = ldi_usage_count();
844 842 bcount = fu_data_size(0);
845 843 if (copyout(&fu_header, (void *)userbp, bcount))
846 844 return (EFAULT);
847 845 return (0);
848 846 }
849 847
850 848 /* get the vnode for the file we want to look up usage for */
851 849 error = lookupname(path, UIO_USERSPACE, FOLLOW, NULLVPP, &fvp);
852 850 if (error != 0)
853 851 return (error);
854 852 ASSERT(fvp);
855 853 fvp_isdev = vn_matchops(fvp, spec_getvnodeops());
856 854
857 855 /*
858 856 * if we want to report usage for all files contained within a
859 857 * file system then the target file better correspond to the
860 858 * root node of a mounted file system, or the root of a zone.
861 859 */
862 860 if (contained && !(fvp->v_flag & VROOT) &&
863 861 fvp != curproc->p_zone->zone_rootvp) {
864 862 error = EINVAL;
865 863 goto out;
866 864 }
867 865
868 866 /*
869 867 * if we want to report usage for all files contained within a
870 868 * file system then the target file better not be a device.
871 869 */
872 870 if (contained && fvp_isdev) {
873 871 error = EINVAL;
874 872 goto out;
875 873 }
876 874
877 875 /*
878 876 * if we want to report usage for a device instance then the
879 877 * target file better corrospond to a device
880 878 */
881 879 if (dip_usage && !fvp_isdev) {
882 880 error = EINVAL;
883 881 goto out;
884 882 }
885 883
886 884 /*
887 885 * if the target vnode isn't a device and it has a reference count
888 886 * of one then no one else is going to have it open so we don't
889 887 * have any work to do.
890 888 */
891 889 if (!fvp_isdev && (fvp->v_count == 1)) {
892 890 goto out;
893 891 }
894 892
895 893 /* look up usage information for this vnode */
896 894 fu_data = dofusers(fvp, flags);
897 895 fuk_data = dofkusers(fvp, flags, &error);
898 896 if (error != 0)
899 897 goto out;
900 898
901 899 /* get a count of the number of f_user_t's we need to copy out */
902 900 total_out = 0;
903 901 if (fu_data)
904 902 total_out += fu_data->fud_user_count;
905 903 if (fuk_data)
906 904 total_out += fuk_data->fud_user_count;
907 905
908 906 /* check if there is enough space to copyout all results */
909 907 if (total_out > total_max) {
910 908 error = E2BIG;
911 909 goto out;
912 910 }
913 911
914 912 /* copyout file usage info counts */
915 913 fu_header.fud_user_max = total_max;
916 914 fu_header.fud_user_count = total_out;
917 915 bcount = fu_data_size(0);
918 916 if (copyout(&fu_header, (void *)userbp, bcount)) {
919 917 error = EFAULT;
920 918 goto out;
921 919 }
922 920
923 921 /* copyout userland process file usage info */
924 922 if ((fu_data != NULL) && (fu_data->fud_user_count > 0)) {
925 923 userbp += bcount;
926 924 bcount = fu_data->fud_user_count * sizeof (f_user_t);
927 925 if (copyout(fu_data->fud_user, (void *)userbp, bcount)) {
928 926 error = EFAULT;
929 927 goto out;
930 928 }
931 929 }
932 930
933 931 /* copyout kernel file usage info */
934 932 if ((fuk_data != NULL) && (fuk_data->fud_user_count > 0)) {
935 933 userbp += bcount;
936 934 bcount = fuk_data->fud_user_count * sizeof (f_user_t);
937 935 if (copyout(fuk_data->fud_user, (void *)userbp, bcount)) {
938 936 error = EFAULT;
939 937 goto out;
940 938 }
941 939 }
942 940
943 941 out:
944 942 /* release the vnode that we were looking up usage for */
945 943 VN_RELE(fvp);
946 944
947 945 /* release any allocated memory */
948 946 if (fu_data)
949 947 kmem_free(fu_data, fu_data_size(fu_data->fud_user_max));
950 948 if (fuk_data)
951 949 kmem_free(fuk_data, fu_data_size(fuk_data->fud_user_max));
952 950
953 951 return (error);
954 952 }
↓ open down ↓ |
399 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX