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