Print this page
6141 use kmem_zalloc instead of kmem_alloc + bzero/memset
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/fs/pcfs/pc_node.c
+++ new/usr/src/uts/common/fs/pcfs/pc_node.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 (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 -#pragma ident "%Z%%M% %I% %E% SMI"
27 -
28 26 #include <sys/param.h>
29 27 #include <sys/t_lock.h>
30 28 #include <sys/errno.h>
31 29 #include <sys/sysmacros.h>
32 30 #include <sys/buf.h>
33 31 #include <sys/systm.h>
34 32 #include <sys/vfs.h>
35 33 #include <sys/vnode.h>
36 34 #include <sys/kmem.h>
37 35 #include <sys/proc.h>
38 36 #include <sys/cred.h>
39 37 #include <sys/cmn_err.h>
40 38 #include <sys/debug.h>
41 39 #include <vm/pvn.h>
42 40 #include <sys/fs/pc_label.h>
43 41 #include <sys/fs/pc_fs.h>
44 42 #include <sys/fs/pc_dir.h>
45 43 #include <sys/fs/pc_node.h>
46 44 #include <sys/dirent.h>
47 45 #include <sys/fdio.h>
48 46 #include <sys/file.h>
49 47 #include <sys/conf.h>
50 48
51 49 struct pchead pcfhead[NPCHASH];
52 50 struct pchead pcdhead[NPCHASH];
53 51
54 52 extern krwlock_t pcnodes_lock;
55 53
56 54 static int pc_getentryblock(struct pcnode *, struct buf **);
57 55 static int syncpcp(struct pcnode *, int);
58 56
59 57 /*
60 58 * fake entry for root directory, since this does not have a parent
61 59 * pointing to it.
62 60 */
63 61 struct pcdir pcfs_rootdirentry = {
64 62 "",
65 63 "",
66 64 PCA_DIR
67 65 };
68 66
69 67 void
70 68 pc_init(void)
71 69 {
72 70 struct pchead *hdp, *hfp;
73 71 int i;
74 72 for (i = 0; i < NPCHASH; i++) {
75 73 hdp = &pcdhead[i];
76 74 hfp = &pcfhead[i];
77 75 hdp->pch_forw = (struct pcnode *)hdp;
78 76 hdp->pch_back = (struct pcnode *)hdp;
79 77 hfp->pch_forw = (struct pcnode *)hfp;
80 78 hfp->pch_back = (struct pcnode *)hfp;
81 79 }
82 80 }
83 81
84 82 struct pcnode *
85 83 pc_getnode(
86 84 struct pcfs *fsp, /* filsystem for node */
87 85 daddr_t blkno, /* phys block no of dir entry */
88 86 int offset, /* offset of dir entry in block */
89 87 struct pcdir *ep) /* node dir entry */
90 88 {
91 89 struct pcnode *pcp;
92 90 struct pchead *hp;
93 91 struct vnode *vp;
94 92 pc_cluster32_t scluster;
95 93
96 94 ASSERT(fsp->pcfs_flags & PCFS_LOCKED);
97 95 if (ep == (struct pcdir *)0) {
98 96 ep = &pcfs_rootdirentry;
99 97 scluster = 0;
100 98 } else {
101 99 scluster = pc_getstartcluster(fsp, ep);
102 100 }
103 101 /*
104 102 * First look for active nodes.
105 103 * File nodes are identified by the location (blkno, offset) of
106 104 * its directory entry.
107 105 * Directory nodes are identified by the starting cluster number
108 106 * for the entries.
109 107 */
110 108 if (ep->pcd_attr & PCA_DIR) {
111 109 hp = &pcdhead[PCDHASH(fsp, scluster)];
112 110 rw_enter(&pcnodes_lock, RW_READER);
113 111 for (pcp = hp->pch_forw;
114 112 pcp != (struct pcnode *)hp; pcp = pcp->pc_forw) {
115 113 if ((fsp == VFSTOPCFS(PCTOV(pcp)->v_vfsp)) &&
116 114 (scluster == pcp->pc_scluster)) {
117 115 VN_HOLD(PCTOV(pcp));
118 116 rw_exit(&pcnodes_lock);
119 117 return (pcp);
120 118 }
121 119 }
122 120 rw_exit(&pcnodes_lock);
123 121 } else {
124 122 hp = &pcfhead[PCFHASH(fsp, blkno, offset)];
125 123 rw_enter(&pcnodes_lock, RW_READER);
126 124 for (pcp = hp->pch_forw;
127 125 pcp != (struct pcnode *)hp; pcp = pcp->pc_forw) {
128 126 if ((fsp == VFSTOPCFS(PCTOV(pcp)->v_vfsp)) &&
129 127 ((pcp->pc_flags & PC_INVAL) == 0) &&
130 128 (blkno == pcp->pc_eblkno) &&
131 129 (offset == pcp->pc_eoffset)) {
132 130 VN_HOLD(PCTOV(pcp));
↓ open down ↓ |
95 lines elided |
↑ open up ↑ |
133 131 rw_exit(&pcnodes_lock);
134 132 return (pcp);
135 133 }
136 134 }
137 135 rw_exit(&pcnodes_lock);
138 136 }
139 137 /*
140 138 * Cannot find node in active list. Allocate memory for a new node
141 139 * initialize it, and put it on the active list.
142 140 */
143 - pcp = kmem_alloc(sizeof (struct pcnode), KM_SLEEP);
144 - bzero(pcp, sizeof (struct pcnode));
141 + pcp = kmem_zalloc(sizeof (struct pcnode), KM_SLEEP);
145 142 vp = vn_alloc(KM_SLEEP);
146 143 pcp->pc_vn = vp;
147 144 pcp->pc_entry = *ep;
148 145 pcp->pc_eblkno = blkno;
149 146 pcp->pc_eoffset = offset;
150 147 pcp->pc_scluster = scluster;
151 148 pcp->pc_lcluster = scluster;
152 149 pcp->pc_lindex = 0;
153 150 pcp->pc_flags = 0;
154 151 if (ep->pcd_attr & PCA_DIR) {
155 152 vn_setops(vp, pcfs_dvnodeops);
156 153 vp->v_type = VDIR;
157 154 if (scluster == 0) {
158 155 vp->v_flag = VROOT;
159 156 blkno = offset = 0;
160 157 if (IS_FAT32(fsp)) {
161 158 pc_cluster32_t ncl = 0;
162 159
163 160 scluster = fsp->pcfs_rdirstart;
164 161 if (pc_fileclsize(fsp, scluster, &ncl)) {
165 162 PC_DPRINTF1(2, "cluster chain "
166 163 "corruption, scluster=%d\n",
167 164 scluster);
168 165 pcp->pc_flags |= PC_INVAL;
169 166 }
170 167 pcp->pc_size = fsp->pcfs_clsize * ncl;
171 168 } else {
172 169 pcp->pc_size =
173 170 fsp->pcfs_rdirsec * fsp->pcfs_secsize;
174 171 }
175 172 } else {
176 173 pc_cluster32_t ncl = 0;
177 174
178 175 if (pc_fileclsize(fsp, scluster, &ncl)) {
179 176 PC_DPRINTF1(2, "cluster chain corruption, "
180 177 "scluster=%d\n", scluster);
181 178 pcp->pc_flags |= PC_INVAL;
182 179 }
183 180 pcp->pc_size = fsp->pcfs_clsize * ncl;
184 181 }
185 182 } else {
186 183 vn_setops(vp, pcfs_fvnodeops);
187 184 vp->v_type = VREG;
188 185 vp->v_flag = VNOSWAP;
189 186 fsp->pcfs_frefs++;
190 187 pcp->pc_size = ltohi(ep->pcd_size);
191 188 }
192 189 fsp->pcfs_nrefs++;
193 190 VFS_HOLD(PCFSTOVFS(fsp));
194 191 vp->v_data = (caddr_t)pcp;
195 192 vp->v_vfsp = PCFSTOVFS(fsp);
196 193 vn_exists(vp);
197 194 rw_enter(&pcnodes_lock, RW_WRITER);
198 195 insque(pcp, hp);
199 196 rw_exit(&pcnodes_lock);
200 197 return (pcp);
201 198 }
202 199
203 200 int
204 201 syncpcp(struct pcnode *pcp, int flags)
205 202 {
206 203 int err;
207 204 if (!vn_has_cached_data(PCTOV(pcp)))
208 205 err = 0;
209 206 else
210 207 err = VOP_PUTPAGE(PCTOV(pcp), 0, 0, flags,
211 208 kcred, NULL);
212 209
213 210 return (err);
214 211 }
215 212
216 213 void
217 214 pc_rele(struct pcnode *pcp)
218 215 {
219 216 struct pcfs *fsp;
220 217 struct vnode *vp;
221 218 int err;
222 219
223 220 vp = PCTOV(pcp);
224 221 PC_DPRINTF1(8, "pc_rele vp=0x%p\n", (void *)vp);
225 222
226 223 fsp = VFSTOPCFS(vp->v_vfsp);
227 224 ASSERT(fsp->pcfs_flags & PCFS_LOCKED);
228 225
229 226 rw_enter(&pcnodes_lock, RW_WRITER);
230 227 pcp->pc_flags |= PC_RELEHOLD;
231 228
232 229 retry:
233 230 if (vp->v_type != VDIR && (pcp->pc_flags & PC_INVAL) == 0) {
234 231 /*
235 232 * If the file was removed while active it may be safely
236 233 * truncated now.
237 234 */
238 235
239 236 if (pcp->pc_entry.pcd_filename[0] == PCD_ERASED) {
240 237 (void) pc_truncate(pcp, 0);
241 238 } else if (pcp->pc_flags & PC_CHG) {
242 239 (void) pc_nodeupdate(pcp);
243 240 }
244 241 err = syncpcp(pcp, B_INVAL);
245 242 if (err) {
246 243 (void) syncpcp(pcp, B_INVAL | B_FORCE);
247 244 }
248 245 }
249 246 if (vn_has_cached_data(vp)) {
250 247 /*
251 248 * pvn_vplist_dirty will abort all old pages
252 249 */
253 250 (void) pvn_vplist_dirty(vp, (u_offset_t)0,
254 251 pcfs_putapage, B_INVAL, (struct cred *)NULL);
255 252 }
256 253
257 254 (void) pc_syncfat(fsp);
258 255 mutex_enter(&vp->v_lock);
259 256 if (vn_has_cached_data(vp)) {
260 257 mutex_exit(&vp->v_lock);
261 258 goto retry;
262 259 }
263 260 ASSERT(!vn_has_cached_data(vp));
264 261
265 262 vp->v_count--; /* release our hold from vn_rele */
266 263 if (vp->v_count > 0) { /* Is this check still needed? */
267 264 PC_DPRINTF1(3, "pc_rele: pcp=0x%p HELD AGAIN!\n", (void *)pcp);
268 265 mutex_exit(&vp->v_lock);
269 266 pcp->pc_flags &= ~PC_RELEHOLD;
270 267 rw_exit(&pcnodes_lock);
271 268 return;
272 269 }
273 270
274 271 remque(pcp);
275 272 rw_exit(&pcnodes_lock);
276 273 /*
277 274 * XXX - old code had a check for !(pcp->pc_flags & PC_INVAL)
278 275 * here. Seems superfluous/incorrect, but then earlier on PC_INVAL
279 276 * was never set anywhere in PCFS. Now it is, and we _have_ to drop
280 277 * the file reference here. Else, we'd screw up umount/modunload.
281 278 */
282 279 if ((vp->v_type == VREG)) {
283 280 fsp->pcfs_frefs--;
284 281 }
285 282 fsp->pcfs_nrefs--;
286 283 VFS_RELE(vp->v_vfsp);
287 284
288 285 if (fsp->pcfs_nrefs < 0) {
289 286 panic("pc_rele: nrefs count");
290 287 }
291 288 if (fsp->pcfs_frefs < 0) {
292 289 panic("pc_rele: frefs count");
293 290 }
294 291
295 292 mutex_exit(&vp->v_lock);
296 293 vn_invalid(vp);
297 294 vn_free(vp);
298 295 kmem_free(pcp, sizeof (struct pcnode));
299 296 }
300 297
301 298 /*
302 299 * Mark a pcnode as modified with the current time.
303 300 */
304 301 /* ARGSUSED */
305 302 void
306 303 pc_mark_mod(struct pcfs *fsp, struct pcnode *pcp)
307 304 {
308 305 timestruc_t now;
309 306
310 307 if (PCTOV(pcp)->v_type == VDIR)
311 308 return;
312 309
313 310 ASSERT(PCTOV(pcp)->v_type == VREG);
314 311
315 312 gethrestime(&now);
316 313 if (pc_tvtopct(&now, &pcp->pc_entry.pcd_mtime))
317 314 PC_DPRINTF1(2, "pc_mark_mod failed timestamp "
318 315 "conversion, curtime = %lld\n",
319 316 (long long)now.tv_sec);
320 317
321 318 pcp->pc_flags |= PC_CHG;
322 319 }
323 320
324 321 /*
325 322 * Mark a pcnode as accessed with the current time.
326 323 */
327 324 void
328 325 pc_mark_acc(struct pcfs *fsp, struct pcnode *pcp)
329 326 {
330 327 struct pctime pt = { 0, 0 };
331 328 timestruc_t now;
332 329
333 330 if (fsp->pcfs_flags & PCFS_NOATIME || PCTOV(pcp)->v_type == VDIR)
334 331 return;
335 332
336 333 ASSERT(PCTOV(pcp)->v_type == VREG);
337 334
338 335 gethrestime(&now);
339 336 if (pc_tvtopct(&now, &pt)) {
340 337 PC_DPRINTF1(2, "pc_mark_acc failed timestamp "
341 338 "conversion, curtime = %lld\n",
342 339 (long long)now.tv_sec);
343 340 return;
344 341 }
345 342
346 343 /*
347 344 * We don't really want to write the adate for every access
348 345 * on flash media; make sure it really changed !
349 346 */
350 347 if (pcp->pc_entry.pcd_ladate != pt.pct_date) {
351 348 pcp->pc_entry.pcd_ladate = pt.pct_date;
352 349 pcp->pc_flags |= (PC_CHG | PC_ACC);
353 350 }
354 351 }
355 352
356 353 /*
357 354 * Truncate a file to a length.
358 355 * Node must be locked.
359 356 */
360 357 int
361 358 pc_truncate(struct pcnode *pcp, uint_t length)
362 359 {
363 360 struct pcfs *fsp;
364 361 struct vnode *vp;
365 362 int error = 0;
366 363
367 364 PC_DPRINTF3(4, "pc_truncate pcp=0x%p, len=%u, size=%u\n",
368 365 (void *)pcp, length, pcp->pc_size);
369 366 vp = PCTOV(pcp);
370 367 if (pcp->pc_flags & PC_INVAL)
371 368 return (EIO);
372 369 fsp = VFSTOPCFS(vp->v_vfsp);
373 370 /*
374 371 * directories are always truncated to zero and are not marked
375 372 */
376 373 if (vp->v_type == VDIR) {
377 374 error = pc_bfree(pcp, 0);
378 375 return (error);
379 376 }
380 377 /*
381 378 * If length is the same as the current size
382 379 * just mark the pcnode and return.
383 380 */
384 381 if (length > pcp->pc_size) {
385 382 daddr_t bno;
386 383 uint_t llcn = howmany((offset_t)length, fsp->pcfs_clsize);
387 384
388 385 /*
389 386 * We are extending a file.
390 387 * Extend it with _one_ call to pc_balloc (no holes)
391 388 * since we don't need to use the block number(s).
392 389 */
393 390 if ((daddr_t)howmany((offset_t)pcp->pc_size, fsp->pcfs_clsize) <
394 391 (daddr_t)llcn) {
395 392 error = pc_balloc(pcp, (daddr_t)(llcn - 1), 1, &bno);
396 393 }
397 394 if (error) {
398 395 pc_cluster32_t ncl = 0;
399 396 PC_DPRINTF1(2, "pc_truncate: error=%d\n", error);
400 397 /*
401 398 * probably ran out disk space;
402 399 * determine current file size
403 400 */
404 401 if (pc_fileclsize(fsp, pcp->pc_scluster, &ncl)) {
405 402 PC_DPRINTF1(2, "cluster chain corruption, "
406 403 "scluster=%d\n", pcp->pc_scluster);
407 404 pcp->pc_flags |= PC_INVAL;
408 405 }
409 406 pcp->pc_size = fsp->pcfs_clsize * ncl;
410 407 } else
411 408 pcp->pc_size = length;
412 409
413 410 } else if (length < pcp->pc_size) {
414 411 /*
415 412 * We are shrinking a file.
416 413 * Free blocks after the block that length points to.
417 414 */
418 415 if (pc_blkoff(fsp, length) == 0) {
419 416 /*
420 417 * Truncation to a block (cluster size) boundary only
421 418 * requires us to invalidate everything after the new
422 419 * end of the file.
423 420 */
424 421 (void) pvn_vplist_dirty(PCTOV(pcp), (u_offset_t)length,
425 422 pcfs_putapage, B_INVAL | B_TRUNC, CRED());
426 423 } else {
427 424 /*
428 425 * pvn_vpzero() cannot deal with more than MAXBSIZE
429 426 * chunks. Since the FAT clustersize can get larger
430 427 * than that, we'll zero from the new length to the
431 428 * end of the cluster for clustersizes smaller than
432 429 * MAXBSIZE - or the end of the MAXBSIZE block in
433 430 * case we've got a large clustersize.
434 431 */
435 432 size_t nbytes =
436 433 roundup(length, MIN(fsp->pcfs_clsize, MAXBSIZE)) -
437 434 length;
438 435
439 436 pvn_vpzero(PCTOV(pcp), (u_offset_t)length, nbytes);
440 437 (void) pvn_vplist_dirty(PCTOV(pcp),
441 438 (u_offset_t)length + nbytes,
442 439 pcfs_putapage, B_INVAL | B_TRUNC, CRED());
443 440 }
444 441 error = pc_bfree(pcp, (pc_cluster32_t)
445 442 howmany((offset_t)length, fsp->pcfs_clsize));
446 443 pcp->pc_size = length;
447 444 }
448 445
449 446 /*
450 447 * This is the only place in PCFS code where pc_mark_mod() is called
451 448 * without setting PC_MOD. May be a historical artifact ...
452 449 */
453 450 pc_mark_mod(fsp, pcp);
454 451 return (error);
455 452 }
456 453
457 454 /*
458 455 * Get block for entry.
459 456 */
460 457 static int
461 458 pc_getentryblock(struct pcnode *pcp, struct buf **bpp)
462 459 {
463 460 struct pcfs *fsp;
464 461
465 462 fsp = VFSTOPCFS(PCTOV(pcp)->v_vfsp);
466 463 if (pcp->pc_eblkno >= fsp->pcfs_datastart ||
467 464 (pcp->pc_eblkno - fsp->pcfs_rdirstart) <
468 465 (fsp->pcfs_rdirsec & ~(fsp->pcfs_spcl - 1))) {
469 466 *bpp = bread(fsp->pcfs_xdev,
470 467 pc_dbdaddr(fsp, pcp->pc_eblkno), fsp->pcfs_clsize);
471 468 } else {
472 469 *bpp = bread(fsp->pcfs_xdev,
473 470 pc_dbdaddr(fsp, pcp->pc_eblkno),
474 471 (int)(fsp->pcfs_datastart - pcp->pc_eblkno) *
475 472 fsp->pcfs_secsize);
476 473 }
477 474 if ((*bpp)->b_flags & B_ERROR) {
478 475 brelse(*bpp);
479 476 pc_mark_irrecov(fsp);
480 477 return (EIO);
481 478 }
482 479 return (0);
483 480 }
484 481
485 482 /*
486 483 * Sync all data associated with a file.
487 484 * Flush all the blocks in the buffer cache out to disk, sync the FAT and
488 485 * update the directory entry.
489 486 */
490 487 int
491 488 pc_nodesync(struct pcnode *pcp)
492 489 {
493 490 struct pcfs *fsp;
494 491 int err;
495 492 struct vnode *vp;
496 493
497 494 vp = PCTOV(pcp);
498 495 fsp = VFSTOPCFS(vp->v_vfsp);
499 496 err = 0;
500 497 if (pcp->pc_flags & PC_MOD) {
501 498 /*
502 499 * Flush all data blocks from buffer cache and
503 500 * update the FAT which points to the data.
504 501 */
505 502 if (err = syncpcp(pcp, 0)) { /* %% ?? how to handle error? */
506 503 if (err == ENOMEM)
507 504 return (err);
508 505 else {
509 506 pc_mark_irrecov(fsp);
510 507 return (EIO);
511 508 }
512 509 }
513 510 pcp->pc_flags &= ~PC_MOD;
514 511 }
515 512 /*
516 513 * update the directory entry
517 514 */
518 515 if (pcp->pc_flags & PC_CHG)
519 516 (void) pc_nodeupdate(pcp);
520 517 return (err);
521 518 }
522 519
523 520 /*
524 521 * Update the node's directory entry.
525 522 */
526 523 int
527 524 pc_nodeupdate(struct pcnode *pcp)
528 525 {
529 526 struct buf *bp;
530 527 int error;
531 528 struct vnode *vp;
532 529 struct pcfs *fsp;
533 530
534 531 vp = PCTOV(pcp);
535 532 fsp = VFSTOPCFS(vp->v_vfsp);
536 533 if (IS_FAT32(fsp) && (vp->v_flag & VROOT)) {
537 534 /* no node to update */
538 535 pcp->pc_flags &= ~(PC_CHG | PC_MOD | PC_ACC);
539 536 return (0);
540 537 }
541 538 if (vp->v_flag & VROOT) {
542 539 panic("pc_nodeupdate");
543 540 }
544 541 if (pcp->pc_flags & PC_INVAL)
545 542 return (0);
546 543 PC_DPRINTF3(7, "pc_nodeupdate pcp=0x%p, bn=%ld, off=%d\n", (void *)pcp,
547 544 pcp->pc_eblkno, pcp->pc_eoffset);
548 545
549 546 if (error = pc_getentryblock(pcp, &bp)) {
550 547 return (error);
551 548 }
552 549 if (vp->v_type == VREG) {
553 550 if (pcp->pc_flags & PC_CHG)
554 551 pcp->pc_entry.pcd_attr |= PCA_ARCH;
555 552 pcp->pc_entry.pcd_size = htoli(pcp->pc_size);
556 553 }
557 554 pc_setstartcluster(fsp, &pcp->pc_entry, pcp->pc_scluster);
558 555 *((struct pcdir *)(bp->b_un.b_addr + pcp->pc_eoffset)) = pcp->pc_entry;
559 556 bwrite2(bp);
560 557 error = geterror(bp);
561 558 brelse(bp);
562 559 if (error) {
563 560 error = EIO;
564 561 pc_mark_irrecov(VFSTOPCFS(vp->v_vfsp));
565 562 }
566 563 pcp->pc_flags &= ~(PC_CHG | PC_MOD | PC_ACC);
567 564 return (error);
568 565 }
569 566
570 567 /*
571 568 * Verify that the disk in the drive is the same one that we
572 569 * got the pcnode from.
573 570 * MUST be called with node unlocked.
574 571 */
575 572 int
576 573 pc_verify(struct pcfs *fsp)
577 574 {
578 575 int fdstatus = 0;
579 576 int error = 0;
580 577
581 578 if (!fsp || fsp->pcfs_flags & PCFS_IRRECOV)
582 579 return (EIO);
583 580
584 581 if (!(fsp->pcfs_flags & PCFS_NOCHK) && fsp->pcfs_fatp) {
585 582 /*
586 583 * This "has it been removed" check should better be
587 584 * modified for removeable media that are not floppies.
588 585 * dkio-managed devices such as USB/firewire external
589 586 * disks/memory sticks/floppies (gasp) do not understand
590 587 * this ioctl.
591 588 */
592 589 PC_DPRINTF1(4, "pc_verify fsp=0x%p\n", (void *)fsp);
593 590 error = cdev_ioctl(fsp->pcfs_vfs->vfs_dev,
594 591 FDGETCHANGE, (intptr_t)&fdstatus, FNATIVE | FKIOCTL,
595 592 NULL, NULL);
596 593
597 594 if (error) {
598 595 if (error == ENOTTY || error == ENXIO) {
599 596 /*
600 597 * See comment above. This is a workaround
601 598 * for removeable media that don't understand
602 599 * floppy ioctls.
603 600 */
604 601 error = 0;
605 602 } else {
606 603 PC_DPRINTF1(1,
607 604 "pc_verify: FDGETCHANGE ioctl failed: %d\n",
608 605 error);
609 606 pc_mark_irrecov(fsp);
610 607 }
611 608 } else if (fsp->pcfs_fatjustread) {
612 609 /*
613 610 * Ignore the results of the ioctl if we just
614 611 * read the FAT. There is a good chance that
615 612 * the disk changed bit will be on, because
616 613 * we've just mounted and we don't want to
617 614 * give a false positive that the sky is falling.
618 615 */
619 616 fsp->pcfs_fatjustread = 0;
620 617 } else {
621 618 /*
622 619 * Oddly enough we can't check just one flag here. The
623 620 * x86 floppy driver sets a different flag
624 621 * (FDGC_DETECTED) than the sparc driver does.
625 622 * I think this MAY be a bug, and I filed 4165938
626 623 * to get someone to look at the behavior
627 624 * a bit more closely. In the meantime, my testing and
628 625 * code examination seem to indicate it is safe to
629 626 * check for either bit being set.
630 627 */
631 628 if (fdstatus & (FDGC_HISTORY | FDGC_DETECTED)) {
632 629 PC_DPRINTF0(1, "pc_verify: change detected\n");
633 630 pc_mark_irrecov(fsp);
634 631 }
635 632 }
636 633 }
637 634 if (error == 0 && fsp->pcfs_fatp == NULL) {
638 635 error = pc_getfat(fsp);
639 636 }
640 637
641 638 return (error);
642 639 }
643 640
644 641 /*
645 642 * The disk has changed, pulling the rug out from beneath us.
646 643 * Mark the FS as being in an irrecoverable state.
647 644 * In a short while we'll clean up.
648 645 */
649 646 void
650 647 pc_mark_irrecov(struct pcfs *fsp)
651 648 {
652 649 if (!(fsp->pcfs_flags & PCFS_NOCHK)) {
653 650 if (pc_lockfs(fsp, 1, 0)) {
654 651 /*
655 652 * Locking failed, which currently would
656 653 * only happen if the FS were already
657 654 * marked as hosed. If another reason for
658 655 * failure were to arise in the future, this
659 656 * routine would have to change.
660 657 */
661 658 return;
662 659 }
663 660
664 661 fsp->pcfs_flags |= PCFS_IRRECOV;
665 662 cmn_err(CE_WARN,
666 663 "Disk was changed during an update or\n"
667 664 "an irrecoverable error was encountered.\n"
668 665 "File damage is possible. To prevent further\n"
669 666 "damage, this pcfs instance will now be frozen.\n"
670 667 "Use umount(1M) to release the instance.\n");
671 668 (void) pc_unlockfs(fsp);
672 669 }
673 670 }
674 671
675 672 /*
676 673 * The disk has been changed!
677 674 */
678 675 void
679 676 pc_diskchanged(struct pcfs *fsp)
680 677 {
681 678 struct pcnode *pcp, *npcp = NULL;
682 679 struct pchead *hp;
683 680 struct vnode *vp;
684 681 extern vfs_t EIO_vfs;
685 682 struct vfs *vfsp;
686 683
687 684 /*
688 685 * Eliminate all pcnodes (dir & file) associated with this fs.
689 686 * If the node is internal, ie, no references outside of
690 687 * pcfs itself, then release the associated vnode structure.
691 688 * Invalidate the in core FAT.
692 689 * Invalidate cached data blocks and blocks waiting for I/O.
693 690 */
694 691 PC_DPRINTF1(1, "pc_diskchanged fsp=0x%p\n", (void *)fsp);
695 692
696 693 vfsp = PCFSTOVFS(fsp);
697 694
698 695 for (hp = pcdhead; hp < &pcdhead[NPCHASH]; hp++) {
699 696 for (pcp = hp->pch_forw;
700 697 pcp != (struct pcnode *)hp; pcp = npcp) {
701 698 npcp = pcp -> pc_forw;
702 699 vp = PCTOV(pcp);
703 700 if ((vp->v_vfsp == vfsp) &&
704 701 !(pcp->pc_flags & PC_RELEHOLD)) {
705 702 mutex_enter(&(vp)->v_lock);
706 703 if (vp->v_count > 0) {
707 704 mutex_exit(&(vp)->v_lock);
708 705 continue;
709 706 }
710 707 mutex_exit(&(vp)->v_lock);
711 708 VN_HOLD(vp);
712 709 remque(pcp);
713 710 vp->v_data = NULL;
714 711 vp->v_vfsp = &EIO_vfs;
715 712 vp->v_type = VBAD;
716 713 VN_RELE(vp);
717 714 if (!(pcp->pc_flags & PC_EXTERNAL)) {
718 715 (void) pvn_vplist_dirty(vp,
719 716 (u_offset_t)0, pcfs_putapage,
720 717 B_INVAL | B_TRUNC,
721 718 (struct cred *)NULL);
722 719 vn_free(vp);
723 720 }
724 721 kmem_free(pcp, sizeof (struct pcnode));
725 722 fsp->pcfs_nrefs --;
726 723 VFS_RELE(vfsp);
727 724 }
728 725 }
729 726 }
730 727 for (hp = pcfhead; fsp->pcfs_frefs && hp < &pcfhead[NPCHASH]; hp++) {
731 728 for (pcp = hp->pch_forw; fsp->pcfs_frefs &&
732 729 pcp != (struct pcnode *)hp; pcp = npcp) {
733 730 npcp = pcp -> pc_forw;
734 731 vp = PCTOV(pcp);
735 732 if ((vp->v_vfsp == vfsp) &&
736 733 !(pcp->pc_flags & PC_RELEHOLD)) {
737 734 mutex_enter(&(vp)->v_lock);
738 735 if (vp->v_count > 0) {
739 736 mutex_exit(&(vp)->v_lock);
740 737 continue;
741 738 }
742 739 mutex_exit(&(vp)->v_lock);
743 740 VN_HOLD(vp);
744 741 remque(pcp);
745 742 vp->v_data = NULL;
746 743 vp->v_vfsp = &EIO_vfs;
747 744 vp->v_type = VBAD;
748 745 VN_RELE(vp);
749 746 if (!(pcp->pc_flags & PC_EXTERNAL)) {
750 747 (void) pvn_vplist_dirty(vp,
751 748 (u_offset_t)0, pcfs_putapage,
752 749 B_INVAL | B_TRUNC,
753 750 (struct cred *)NULL);
754 751 vn_free(vp);
755 752 }
756 753 kmem_free(pcp, sizeof (struct pcnode));
757 754 fsp->pcfs_frefs--;
758 755 fsp->pcfs_nrefs--;
759 756 VFS_RELE(vfsp);
760 757 }
761 758 }
762 759 }
763 760 #ifdef undef
764 761 if (fsp->pcfs_frefs) {
765 762 rw_exit(&pcnodes_lock);
766 763 panic("pc_diskchanged: frefs");
767 764 }
768 765 if (fsp->pcfs_nrefs) {
769 766 rw_exit(&pcnodes_lock);
770 767 panic("pc_diskchanged: nrefs");
771 768 }
772 769 #endif
773 770 if (!(vfsp->vfs_flag & VFS_UNMOUNTED) &&
774 771 fsp->pcfs_fatp != (uchar_t *)0) {
775 772 pc_invalfat(fsp);
776 773 } else {
777 774 binval(fsp->pcfs_xdev);
778 775 }
779 776 }
↓ open down ↓ |
625 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX